add first launch info
This commit is contained in:
parent
ad73ce0571
commit
6918c5e2a5
3 changed files with 103 additions and 27 deletions
|
|
@ -20,7 +20,7 @@ a = Analysis(
|
||||||
['disco-reaper.py'],
|
['disco-reaper.py'],
|
||||||
pathex=[],
|
pathex=[],
|
||||||
binaries=[],
|
binaries=[],
|
||||||
datas=[],
|
datas=[('src/first-info.md', 'src')],
|
||||||
hiddenimports=hiddenimports,
|
hiddenimports=hiddenimports,
|
||||||
hookspath=[],
|
hookspath=[],
|
||||||
hooksconfig={},
|
hooksconfig={},
|
||||||
|
|
|
||||||
24
src/first-info.md
Normal file
24
src/first-info.md
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
# Welcome to the Reaper
|
||||||
|
|
||||||
|
> **The goal isn't just to leave Discord - it's to build a future where online communities don't require surrendering your biometric data and identity documents to participate. [Learn More](https://github.com/DukePantarei/discord-alternatives-wishlist/blob/main/BACKGROUND.md)**
|
||||||
|
|
||||||
|
Reaper tool solely exists to preserve your Server's message history and help you migrate to better platforms which actually respect you.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Important Note
|
||||||
|
- The **migrated messages cannot be edited or deleted** by the original sender.
|
||||||
|
- So make sure to **get permission from fellow members** if you're using this tool on **private servers**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Join our Community
|
||||||
|
- Join the **Reaper Community** if you need any help.
|
||||||
|
- Provide your suggestions / request new features.
|
||||||
|
- Invite link: https://fluxer.gg/2jlTwB0w
|
||||||
|
|
||||||
|
`This tool was developed independently. Not affiliated with or endorsed by Fluxer, Stoat or Discord.`
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -6,10 +6,10 @@ from pathlib import Path
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
from textual.app import App, ComposeResult
|
from textual.app import App, ComposeResult
|
||||||
from textual.containers import Container, Horizontal, Vertical, VerticalScroll
|
from textual.containers import Container, Horizontal, Vertical, VerticalScroll, Center
|
||||||
from textual.widgets import (
|
from textual.widgets import (
|
||||||
Header, Footer, Button, Label, Input, ListItem,
|
Header, Footer, Button, Label, Input, ListItem,
|
||||||
ListView, Rule, RadioButton, RadioSet, Select, Static,
|
ListView, Rule, RadioButton, RadioSet, Select, Static, Markdown
|
||||||
)
|
)
|
||||||
from textual.screen import Screen, ModalScreen
|
from textual.screen import Screen, ModalScreen
|
||||||
|
|
||||||
|
|
@ -21,9 +21,46 @@ from src.core.utils import get_app_version
|
||||||
|
|
||||||
|
|
||||||
# ──────────────────────────────────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────────────────────────────────
|
||||||
# Modal: create a new ReaperFiles-* config folder
|
# Modals
|
||||||
# ──────────────────────────────────────────────────────────────────────────────
|
# ──────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
class FirstInfoModal(ModalScreen[str]):
|
||||||
|
"""Modal to display first-time launch info."""
|
||||||
|
|
||||||
|
DEFAULT_CSS = """
|
||||||
|
FirstInfoModal { align: center middle; }
|
||||||
|
#first_info_dialog {
|
||||||
|
width: 80%; height: auto; max-height: 80%;
|
||||||
|
border: thick $background 80%; background: $surface; padding: 1 2;
|
||||||
|
}
|
||||||
|
#btn_yeah { width: 100%; margin-top: 1; }
|
||||||
|
"""
|
||||||
|
|
||||||
|
def compose(self) -> ComposeResult:
|
||||||
|
with VerticalScroll(id="first_info_dialog"):
|
||||||
|
try:
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Handle PyInstaller path resolution
|
||||||
|
if getattr(sys, 'frozen', False):
|
||||||
|
base_path = sys._MEIPASS
|
||||||
|
else:
|
||||||
|
base_path = os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))
|
||||||
|
|
||||||
|
file_path = os.path.join(base_path, "src", "first-info.md")
|
||||||
|
|
||||||
|
with open(file_path, "r", encoding="utf-8") as f:
|
||||||
|
md_text = f.read()
|
||||||
|
except Exception as e:
|
||||||
|
md_text = f"# Welcome to the Reaper\n\nInfo text missing. ({e})"
|
||||||
|
yield Markdown(md_text)
|
||||||
|
yield Button("Get Started", variant="success", id="btn_yeah")
|
||||||
|
|
||||||
|
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||||
|
if event.button.id == "btn_yeah":
|
||||||
|
self.dismiss("start_new")
|
||||||
|
|
||||||
class NewConfigModal(ModalScreen[str]):
|
class NewConfigModal(ModalScreen[str]):
|
||||||
"""Modal to enter a name for a new configuration."""
|
"""Modal to enter a name for a new configuration."""
|
||||||
|
|
||||||
|
|
@ -90,10 +127,12 @@ class ConfigSelectionScreen(Screen):
|
||||||
}
|
}
|
||||||
#config_sel_actions { height: auto; margin-top: 0; }
|
#config_sel_actions { height: auto; margin-top: 0; }
|
||||||
#config_sel_actions Button { width: 1fr; margin: 0 1; }
|
#config_sel_actions Button { width: 1fr; margin: 0 1; }
|
||||||
|
#btn_about { margin-top: 2; border: none; }
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def compose(self) -> ComposeResult:
|
def compose(self) -> ComposeResult:
|
||||||
yield Header(show_clock=True)
|
yield Header(show_clock=True)
|
||||||
|
with Center():
|
||||||
with Container(id="config_sel_container"):
|
with Container(id="config_sel_container"):
|
||||||
yield Label(f"{get_app_version()} — Select Configuration", id="config_sel_title")
|
yield Label(f"{get_app_version()} — Select Configuration", id="config_sel_title")
|
||||||
with VerticalScroll(id="config_list_container"):
|
with VerticalScroll(id="config_list_container"):
|
||||||
|
|
@ -101,22 +140,30 @@ class ConfigSelectionScreen(Screen):
|
||||||
with Horizontal(id="config_sel_actions"):
|
with Horizontal(id="config_sel_actions"):
|
||||||
yield Button("New Config", id="btn_new_config", variant="success", tooltip="Create a new configuration folder")
|
yield Button("New Config", id="btn_new_config", variant="success", tooltip="Create a new configuration folder")
|
||||||
yield Button("Exit", id="btn_exit", variant="error")
|
yield Button("Exit", id="btn_exit", variant="error")
|
||||||
|
with Center():
|
||||||
|
yield Button("Info", id="btn_about", tooltip="Show app information")
|
||||||
yield Footer()
|
yield Footer()
|
||||||
yield Footnote()
|
yield Footnote()
|
||||||
yield RamDisplay()
|
yield RamDisplay()
|
||||||
|
|
||||||
def on_mount(self) -> None:
|
def on_mount(self) -> None:
|
||||||
self.refresh_configs()
|
configs = self.refresh_configs()
|
||||||
|
if not configs:
|
||||||
|
def on_first_info_dismiss(res):
|
||||||
|
if res == "start_new":
|
||||||
|
self.action_new_config()
|
||||||
|
self.app.push_screen(FirstInfoModal(), on_first_info_dismiss)
|
||||||
|
|
||||||
def on_screen_resume(self) -> None:
|
def on_screen_resume(self) -> None:
|
||||||
self.refresh_configs()
|
self.refresh_configs()
|
||||||
|
|
||||||
def refresh_configs(self) -> None:
|
def refresh_configs(self) -> list:
|
||||||
configs = get_available_configs()
|
configs = get_available_configs()
|
||||||
lv = self.query_one("#config_list", ListView)
|
lv = self.query_one("#config_list", ListView)
|
||||||
lv.clear()
|
lv.clear()
|
||||||
for c in configs:
|
for c in configs:
|
||||||
lv.append(ListItem(Label(c), name=c))
|
lv.append(ListItem(Label(c), name=c))
|
||||||
|
return configs
|
||||||
|
|
||||||
def on_list_view_selected(self, event: ListView.Selected) -> None:
|
def on_list_view_selected(self, event: ListView.Selected) -> None:
|
||||||
cfg_name = event.item.name
|
cfg_name = event.item.name
|
||||||
|
|
@ -124,8 +171,7 @@ class ConfigSelectionScreen(Screen):
|
||||||
from src.ui.mode_screen import ModeScreen
|
from src.ui.mode_screen import ModeScreen
|
||||||
self.app.push_screen(ModeScreen(cfg_name, cfg_path))
|
self.app.push_screen(ModeScreen(cfg_name, cfg_path))
|
||||||
|
|
||||||
def on_button_pressed(self, event: Button.Pressed) -> None:
|
def action_new_config(self) -> None:
|
||||||
if event.button.id == "btn_new_config":
|
|
||||||
def cb(name: str | None):
|
def cb(name: str | None):
|
||||||
if name:
|
if name:
|
||||||
create_new_config(name)
|
create_new_config(name)
|
||||||
|
|
@ -140,6 +186,12 @@ class ConfigSelectionScreen(Screen):
|
||||||
self.app.push_screen(ModeScreen(name, cfg_path))
|
self.app.push_screen(ModeScreen(name, cfg_path))
|
||||||
self.app.push_screen(ConfigScreen(name, cfg_path), on_config_saved)
|
self.app.push_screen(ConfigScreen(name, cfg_path), on_config_saved)
|
||||||
self.app.push_screen(NewConfigModal(), cb)
|
self.app.push_screen(NewConfigModal(), cb)
|
||||||
|
|
||||||
|
def on_button_pressed(self, event: Button.Pressed) -> None:
|
||||||
|
if event.button.id == "btn_new_config":
|
||||||
|
self.action_new_config()
|
||||||
|
elif event.button.id == "btn_about":
|
||||||
|
self.app.push_screen(FirstInfoModal())
|
||||||
elif event.button.id == "btn_exit":
|
elif event.button.id == "btn_exit":
|
||||||
self.app.exit()
|
self.app.exit()
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue