mirror of
https://github.com/bombsquad-community/plugin-manager.git
synced 2025-10-08 14:54:36 +00:00
Add UI for adding 3rd party plugins (tested for UIScale.LARGE rn)
This commit is contained in:
parent
5a2144fa88
commit
607663d2ac
1 changed files with 229 additions and 127 deletions
|
|
@ -16,6 +16,7 @@ from typing import Union, Optional
|
|||
_env = _ba.env()
|
||||
_uiscale = ba.app.ui.uiscale
|
||||
|
||||
|
||||
# XXX: Using https with `ba.open_url` seems to trigger a pop-up dialog box on Android currently (v1.7.6)
|
||||
# and won't open the actual URL in a web-browser. Let's fallback to http for now until this
|
||||
# gets resolved.
|
||||
|
|
@ -45,8 +46,8 @@ def setup_config():
|
|||
if "Installed Plugins" not in ba.app.config["Community Plugin Manager"]:
|
||||
ba.app.config["Community Plugin Manager"]["Installed Plugins"] = {}
|
||||
is_config_updated = True
|
||||
if "Custom Categories" not in ba.app.config["Community Plugin Manager"]:
|
||||
ba.app.config["Community Plugin Manager"]["Custom Categories"] = []
|
||||
if "Custom Sources" not in ba.app.config["Community Plugin Manager"]:
|
||||
ba.app.config["Community Plugin Manager"]["Custom Sources"] = []
|
||||
is_config_updated = True
|
||||
for plugin_name in ba.app.config["Community Plugin Manager"]["Installed Plugins"].keys():
|
||||
plugin = PluginLocal(plugin_name)
|
||||
|
|
@ -110,25 +111,35 @@ class Category:
|
|||
self.set_category_global_cache("metadata", self._metadata)
|
||||
return self
|
||||
|
||||
async def is_valid(self):
|
||||
await self.fetch_metadata()
|
||||
try:
|
||||
await asyncio.gather(
|
||||
self.get_name(),
|
||||
self.get_description(),
|
||||
self.get_plugins_base_url(),
|
||||
self.get_plugins(),
|
||||
)
|
||||
except KeyError:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
async def get_name(self):
|
||||
if self._metadata is None:
|
||||
await self.fetch_metadata()
|
||||
await self.fetch_metadata()
|
||||
return self._metadata["name"]
|
||||
|
||||
async def get_description(self):
|
||||
if self._metadata is None:
|
||||
await self.fetch_metadata()
|
||||
await self.fetch_metadata()
|
||||
return self._metadata["description"]
|
||||
|
||||
async def get_plugins_base_url(self):
|
||||
if self._metadata is None:
|
||||
await self.fetch_metadata()
|
||||
await self.fetch_metadata()
|
||||
return self._metadata["plugins_base_url"]
|
||||
|
||||
async def get_plugins(self):
|
||||
if self._plugins is None:
|
||||
if self._metadata is None:
|
||||
await self.fetch_metadata()
|
||||
await self.fetch_metadata()
|
||||
self._plugins = ([
|
||||
Plugin(
|
||||
plugin_info,
|
||||
|
|
@ -162,6 +173,10 @@ class Category:
|
|||
self._plugins.clear()
|
||||
self.unset_category_global_cache()
|
||||
|
||||
def save(self):
|
||||
ba.app.config["Community Plugin Manager"]["Custom Sources"].append(self.meta_url)
|
||||
ba.app.config.commit()
|
||||
|
||||
|
||||
class CategoryAll(Category):
|
||||
def __init__(self, plugins={}):
|
||||
|
|
@ -407,6 +422,7 @@ class PluginWindow(popup.PopupWindow):
|
|||
text_scale = 0.7 * s
|
||||
self._transition_out = 'out_scale'
|
||||
transition = 'in_scale'
|
||||
|
||||
self._root_widget = ba.containerwidget(size=(width, height),
|
||||
parent=_ba.get_special_widget(
|
||||
'overlay_stack'),
|
||||
|
|
@ -415,6 +431,7 @@ class PluginWindow(popup.PopupWindow):
|
|||
scale=(2.1 if _uiscale is ba.UIScale.SMALL else 1.5
|
||||
if _uiscale is ba.UIScale.MEDIUM else 1.0),
|
||||
scale_origin_stack_offset=self.scale_origin)
|
||||
|
||||
pos = height * 0.8
|
||||
plugin_title = f"{self.plugin.name} (v{self.plugin.latest_version})"
|
||||
ba.textwidget(parent=self._root_widget,
|
||||
|
|
@ -604,7 +621,7 @@ class PluginManager:
|
|||
category = Category(plugin_category_url)
|
||||
request = category.fetch_metadata()
|
||||
requests.append(request)
|
||||
for repository in ba.app.config["Community Plugin Manager"]["Custom Categories"]:
|
||||
for repository in ba.app.config["Community Plugin Manager"]["Custom Sources"]:
|
||||
plugin_category_url = THIRD_PARTY_CATEGORY_URL.replace("{repository}", "$repository")
|
||||
plugin_category_url = string.Template(plugin_category_url).safe_substitute({
|
||||
"repository": repository,
|
||||
|
|
@ -644,6 +661,180 @@ class PluginManager:
|
|||
pass
|
||||
|
||||
|
||||
class PluginSourcesWindow(popup.PopupWindow):
|
||||
def __init__(self, origin_widget):
|
||||
play_sound()
|
||||
|
||||
self.scale_origin = origin_widget.get_screen_space_center()
|
||||
|
||||
b_text_color = (0.75, 0.7, 0.8)
|
||||
s = 1.1 if _uiscale is ba.UIScale.SMALL else 1.27 if ba.UIScale.MEDIUM else 1.57
|
||||
text_scale = 0.7 * s
|
||||
self._transition_out = 'out_scale'
|
||||
transition = 'in_scale'
|
||||
self._root_widget = ba.containerwidget(size=(400, 340),
|
||||
parent=_ba.get_special_widget(
|
||||
'overlay_stack'),
|
||||
on_outside_click_call=self._ok,
|
||||
transition=transition,
|
||||
scale=(2.1 if _uiscale is ba.UIScale.SMALL else 1.5
|
||||
if _uiscale is ba.UIScale.MEDIUM else 1.0),
|
||||
scale_origin_stack_offset=self.scale_origin,
|
||||
on_cancel_call=self._ok)
|
||||
|
||||
scroll_size_x = (400 if _uiscale is ba.UIScale.SMALL else
|
||||
380 if _uiscale is ba.UIScale.MEDIUM else 290)
|
||||
scroll_size_y = (225 if _uiscale is ba.UIScale.SMALL else
|
||||
235 if _uiscale is ba.UIScale.MEDIUM else 180)
|
||||
scroll_pos_x = (70 if _uiscale is ba.UIScale.SMALL else
|
||||
40 if _uiscale is ba.UIScale.MEDIUM else 60)
|
||||
scroll_pos_y = (125 if _uiscale is ba.UIScale.SMALL else
|
||||
30 if _uiscale is ba.UIScale.MEDIUM else 105)
|
||||
self._scrollwidget = ba.scrollwidget(parent=self._root_widget,
|
||||
size=(scroll_size_x, scroll_size_y),
|
||||
position=(scroll_pos_x, scroll_pos_y))
|
||||
self._columnwidget = ba.columnwidget(parent=self._scrollwidget,
|
||||
border=1,
|
||||
margin=0)
|
||||
|
||||
ba.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(155, 300),
|
||||
size=(100, 25),
|
||||
text="Plugin Sources",
|
||||
color=ba.app.ui.title_color,
|
||||
scale=0.8,
|
||||
h_align="center",
|
||||
v_align="center",
|
||||
maxwidth=270,
|
||||
)
|
||||
|
||||
self._add_source_widget = ba.textwidget(parent=self._root_widget,
|
||||
text="rikkolovescats/sahilp-plugins",
|
||||
size=(335, 50),
|
||||
position=(21, 30),
|
||||
h_align='left',
|
||||
v_align='center',
|
||||
editable=True,
|
||||
scale=0.75,
|
||||
maxwidth=215,
|
||||
description="Add Source")
|
||||
|
||||
b_textcolor = (0.75, 0.7, 0.8)
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
ba.buttonwidget(parent=self._root_widget,
|
||||
position=(330, 36),
|
||||
size=(37, 37),
|
||||
on_activate_call=lambda: loop.create_task(self.add_source()),
|
||||
label="",
|
||||
texture=ba.gettexture("startButton"),
|
||||
# texture=ba.gettexture("chestOpenIcon"),
|
||||
button_type="square",
|
||||
color=(0, 0.9, 0),
|
||||
textcolor=b_textcolor,
|
||||
autoselect=True,
|
||||
text_scale=1)
|
||||
|
||||
ba.buttonwidget(parent=self._root_widget,
|
||||
position=(360, 110),
|
||||
size=(30, 30),
|
||||
on_activate_call=self.delete_selected_source,
|
||||
label="",
|
||||
texture=ba.gettexture("crossOut"),
|
||||
button_type="square",
|
||||
color=(5, 0.8, 0.8),
|
||||
textcolor=b_textcolor,
|
||||
autoselect=True,
|
||||
text_scale=1)
|
||||
self.draw_sources()
|
||||
|
||||
def draw_sources(self):
|
||||
for plugin in self._columnwidget.get_children():
|
||||
plugin.delete()
|
||||
|
||||
color = (1, 1, 1)
|
||||
for custom_source in ba.app.config["Community Plugin Manager"]["Custom Sources"]:
|
||||
ba.textwidget(parent=self._columnwidget,
|
||||
# size=(410, 30),
|
||||
selectable=True,
|
||||
always_highlight=True,
|
||||
color=color,
|
||||
text=custom_source,
|
||||
# click_activate=True,
|
||||
on_select_call=lambda: self.select_source(custom_source),
|
||||
h_align='left',
|
||||
v_align='center',
|
||||
scale=0.75,
|
||||
maxwidth=260)
|
||||
|
||||
|
||||
def select_source(self, source):
|
||||
self.selected_source = source
|
||||
|
||||
async def add_source(self):
|
||||
source = ba.textwidget(query=self._add_source_widget)
|
||||
meta_url = THIRD_PARTY_CATEGORY_URL.format(repository=source, content_type="raw")
|
||||
category = Category(meta_url, is_3rd_party=True)
|
||||
if source in ba.app.config["Community Plugin Manager"]["Custom Sources"]:
|
||||
ba.screenmessage("Plugin source already exists")
|
||||
return
|
||||
if not await category.is_valid():
|
||||
ba.screenmessage("Enter a valid plugin source")
|
||||
return
|
||||
ba.app.config["Community Plugin Manager"]["Custom Sources"].append(source)
|
||||
ba.app.config.commit()
|
||||
ba.screenmessage("Plugin source added")
|
||||
self.draw_sources()
|
||||
|
||||
def delete_selected_source(self):
|
||||
ba.app.config["Community Plugin Manager"]["Custom Sources"].remove(self.selected_source)
|
||||
ba.app.config.commit()
|
||||
self.draw_sources()
|
||||
|
||||
def _ok(self) -> None:
|
||||
play_sound()
|
||||
ba.containerwidget(edit=self._root_widget, transition='out_scale')
|
||||
|
||||
def get_custom_sources():
|
||||
return ba.app.config["Community Plugin Manager"]["Custom Sources"]
|
||||
|
||||
|
||||
class CategoryWindow(popup.PopupMenuWindow):
|
||||
def __init__(self, choices, current_choice, origin_widget, asyncio_callback):
|
||||
choices = (*choices, "Custom Sources")
|
||||
self._asyncio_callback = asyncio_callback
|
||||
self.scale_origin = origin_widget.get_screen_space_center()
|
||||
super().__init__(
|
||||
position=(200, 0),
|
||||
scale=(2.3 if _uiscale is ba.UIScale.SMALL else
|
||||
1.65 if _uiscale is ba.UIScale.MEDIUM else 1.23),
|
||||
choices=choices,
|
||||
current_choice=current_choice,
|
||||
delegate=self)
|
||||
self._update_custom_sources_widget()
|
||||
|
||||
def _update_custom_sources_widget(self):
|
||||
ba.textwidget(edit=self._columnwidget.get_children()[-1],
|
||||
color=(0.5, 0.5, 0.5),
|
||||
on_activate_call=self.show_sources_window)
|
||||
|
||||
def popup_menu_selected_choice(self, window, choice):
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.create_task(self._asyncio_callback(choice))
|
||||
|
||||
def popup_menu_closing(self, window):
|
||||
pass
|
||||
|
||||
def show_sources_window(self):
|
||||
self._ok()
|
||||
PluginSourcesWindow(origin_widget=self.root_widget)
|
||||
|
||||
def _ok(self) -> None:
|
||||
play_sound()
|
||||
ba.containerwidget(edit=self.root_widget, transition='out_scale')
|
||||
|
||||
|
||||
class PluginManagerWindow(ba.Window):
|
||||
def __init__(self, transition: str = "in_right", origin_widget: ba.Widget = None):
|
||||
self.plugin_manager = PluginManager()
|
||||
|
|
@ -736,71 +927,6 @@ class PluginManagerWindow(ba.Window):
|
|||
border=2,
|
||||
margin=0)
|
||||
|
||||
# name = ba.textwidget(parent=self._columnwidget,
|
||||
# size=(410, 30),
|
||||
# selectable=True, always_highlight=True,
|
||||
# color=(1,1,1),
|
||||
# on_select_call=lambda: None,
|
||||
# text="ColorScheme",
|
||||
# on_activate_call=lambda: None,
|
||||
# h_align='left', v_align='center',
|
||||
# maxwidth=420)
|
||||
|
||||
# v = (self._height - 75) if _uiscale is ba.UIScale.SMALL else (self._height - 59)
|
||||
|
||||
# h = 40
|
||||
# b_textcolor = (0.75, 0.7, 0.8)
|
||||
# b_color = (0.6, 0.53, 0.63)
|
||||
|
||||
# s = (1.0 if _uiscale is ba.UIScale.SMALL else
|
||||
# 1.27 if _uiscale is ba.UIScale.MEDIUM else 1.57)
|
||||
# b_size = (90, 60 * s)
|
||||
# v -= 63 * s
|
||||
|
||||
# self.reload_button = ba.buttonwidget(parent=self._root_widget,
|
||||
# position=(h, v), size=b_size,
|
||||
# on_activate_call=self._refresh,
|
||||
# label="Reload List",
|
||||
# button_type="square",
|
||||
# color=b_color,
|
||||
# textcolor=b_textcolor,
|
||||
# autoselect=True, text_scale=0.7)
|
||||
# v -= 63 * s
|
||||
# self.info_button = ba.buttonwidget(parent=self._root_widget,
|
||||
# position=(h, v), size=b_size,
|
||||
# on_activate_call=self._get_info,
|
||||
# label="Mod Info",
|
||||
# button_type="square", color=b_color,
|
||||
# textcolor=b_textcolor,
|
||||
# autoselect=True, text_scale=0.7)
|
||||
# v -= 63 * s
|
||||
# self.sort_button = ba.buttonwidget(parent=self._root_widget,
|
||||
# position=(h, v), size=b_size,
|
||||
# on_activate_call=self._sort,
|
||||
# label="Sort\nAlphabetical",
|
||||
# button_type="square", color=b_color,
|
||||
# textcolor=b_textcolor,
|
||||
# text_scale=0.7, autoselect=True)
|
||||
# v -= 63 * s
|
||||
# self.settings_button = ba.buttonwidget(parent=self._root_widget,
|
||||
# position=(h, v), size=b_size,
|
||||
# on_activate_call=self._settings,
|
||||
# label="Settings",
|
||||
# button_type="square",
|
||||
# color=b_color,
|
||||
# textcolor=b_textcolor,
|
||||
# autoselect=True, text_scale=0.7)
|
||||
# self.column_pos_y = self._height - 75 - self.tab_height
|
||||
# self._scroll_width = self._width - 180
|
||||
# self._scroll_height = self._height - 120 - self.tab_height
|
||||
# self._scrollwidget = ba.scrollwidget(parent=self._root_widget, size=(
|
||||
# self._scroll_width, self._scroll_height), position=(
|
||||
# 140, self.column_pos_y - self._scroll_height + 10))
|
||||
# self._columnwidget = ba.columnwidget(parent=self._scrollwidget,
|
||||
# border=2, margin=0)
|
||||
# self._mod_selected = None
|
||||
# self._refresh()
|
||||
|
||||
def _back(self) -> None:
|
||||
play_sound()
|
||||
from bastd.ui.settings.allsettings import AllSettingsWindow
|
||||
|
|
@ -827,20 +953,10 @@ class PluginManagerWindow(ba.Window):
|
|||
text="Make sure you are connected\n to the Internet and try again.")
|
||||
|
||||
async def draw_category_selection_button(self, post_label):
|
||||
# v = (self._height - 75) if _uiscale is ba.UIScale.SMALL else (self._height - 105)
|
||||
# v = 395
|
||||
# h = 440
|
||||
# category_pos_x = 15 + (0 if _uiscale is ba.UIScale.SMALL else
|
||||
# 17 if _uiscale is ba.UIScale.MEDIUM else 58)
|
||||
category_pos_x = (330 if _uiscale is ba.UIScale.SMALL else
|
||||
285 if _uiscale is ba.UIScale.MEDIUM else 350)
|
||||
category_pos_y = self._height - (145 if _uiscale is ba.UIScale.SMALL else
|
||||
110 if _uiscale is ba.UIScale.MEDIUM else 110)
|
||||
# the next 2 lines belong in 1 line
|
||||
# # s = 1.0 if _uiscale is ba.UIScale.SMALL else
|
||||
# # 1.27 if _uiscale is ba.UIScale.MEDIUM else 1.57
|
||||
# s = 1.75
|
||||
# b_size = (90, 60 * s)
|
||||
b_size = (140, 30)
|
||||
b_textcolor = (0.75, 0.7, 0.8)
|
||||
b_color = (0.6, 0.53, 0.63)
|
||||
|
|
@ -852,7 +968,7 @@ class PluginManagerWindow(ba.Window):
|
|||
position=(category_pos_x,
|
||||
category_pos_y),
|
||||
size=b_size,
|
||||
on_activate_call=lambda: self.show_categories(),
|
||||
on_activate_call=self.show_categories_window,
|
||||
label=label,
|
||||
button_type="square",
|
||||
color=b_color,
|
||||
|
|
@ -868,22 +984,32 @@ class PluginManagerWindow(ba.Window):
|
|||
55 if _uiscale is ba.UIScale.MEDIUM else 90)
|
||||
search_bar_pos_y = self._height - (
|
||||
145 if _uiscale is ba.UIScale.SMALL else
|
||||
110 if _uiscale is ba.UIScale.MEDIUM else 120)
|
||||
110 if _uiscale is ba.UIScale.MEDIUM else 116)
|
||||
|
||||
search_bar_size_x = (250 if _uiscale is ba.UIScale.SMALL else
|
||||
230 if _uiscale is ba.UIScale.MEDIUM else 250)
|
||||
230 if _uiscale is ba.UIScale.MEDIUM else 260)
|
||||
search_bar_size_y = (
|
||||
35 if _uiscale is ba.UIScale.SMALL else
|
||||
35 if _uiscale is ba.UIScale.MEDIUM else 45)
|
||||
|
||||
ba.textwidget(parent=self._root_widget,
|
||||
text="Filter",
|
||||
position=(60, search_bar_pos_y + 8),
|
||||
selectable=False,
|
||||
h_align='left',
|
||||
v_align='center',
|
||||
color=ba.app.ui.title_color,
|
||||
scale=0.5)
|
||||
|
||||
filter_txt = ba.Lstr(resource='filterText')
|
||||
self._filter_text = ba.textwidget(parent=self._root_widget,
|
||||
text="Search",
|
||||
self._filter_widget = ba.textwidget(parent=self._root_widget,
|
||||
text="",
|
||||
size=(search_bar_size_x, search_bar_size_y),
|
||||
position=(search_bar_pos_x, search_bar_pos_y),
|
||||
h_align='left',
|
||||
v_align='center',
|
||||
editable=True,
|
||||
scale=0.8,
|
||||
description=filter_txt)
|
||||
|
||||
async def draw_settings_icon(self):
|
||||
|
|
@ -926,16 +1052,6 @@ class PluginManagerWindow(ba.Window):
|
|||
draw_controller=controller_button)
|
||||
|
||||
async def draw_plugin_names(self, category):
|
||||
# v = (self._height - 75) if _uiscale is ba.UIScale.SMALL else (self._height - 105)
|
||||
# h = 440
|
||||
# next 2 lines belong in 1 line
|
||||
# # s = 1.0 if _uiscale is ba.UIScale.SMALL else
|
||||
# # 1.27 if _uiscale is ba.UIScale.MEDIUM else 1.57
|
||||
# s = 1.75
|
||||
# # b_size = (90, 60 * s)
|
||||
# b_size = (150, 30)
|
||||
# b_textcolor = (0.75, 0.7, 0.8)
|
||||
# b_color = (0.6, 0.53, 0.63)
|
||||
for plugin in self._columnwidget.get_children():
|
||||
plugin.delete()
|
||||
|
||||
|
|
@ -971,27 +1087,23 @@ class PluginManagerWindow(ba.Window):
|
|||
# on_select_call=lambda: None,
|
||||
text=plugin.name,
|
||||
click_activate=True,
|
||||
on_activate_call=ba.Call(PluginWindow, plugin,
|
||||
self._root_widget,
|
||||
(lambda:
|
||||
self.draw_plugin_name(plugin))),
|
||||
on_activate_call=lambda: self.show_plugin_window(plugin),
|
||||
h_align='left',
|
||||
v_align='center',
|
||||
maxwidth=420)
|
||||
self.plugins_in_current_view[plugin.name] = text_widget
|
||||
|
||||
def show_categories(self):
|
||||
def show_plugin_window(self, plugin):
|
||||
PluginWindow(plugin, self._root_widget, lambda: self.draw_plugin_name(plugin))
|
||||
|
||||
def show_categories_window(self):
|
||||
play_sound()
|
||||
# On each new entry, change position to y -= 40.
|
||||
# value = bastd.ui.popup.PopupMenuWindow(
|
||||
bastd.ui.popup.PopupMenuWindow(
|
||||
# position=(200, 40),
|
||||
position=(200, 0),
|
||||
scale=(2.3 if _uiscale is ba.UIScale.SMALL else
|
||||
1.65 if _uiscale is ba.UIScale.MEDIUM else 1.23),
|
||||
choices=self.plugin_manager.categories.keys(),
|
||||
current_choice=self.selected_category,
|
||||
delegate=self)
|
||||
CategoryWindow(
|
||||
self.plugin_manager.categories.keys(),
|
||||
self.selected_category,
|
||||
self._root_widget,
|
||||
self.select_category,
|
||||
)
|
||||
|
||||
async def select_category(self, category):
|
||||
self.selected_category = category
|
||||
|
|
@ -999,13 +1111,6 @@ class PluginManagerWindow(ba.Window):
|
|||
await self.draw_category_selection_button(post_label=category)
|
||||
await self.draw_plugin_names(category)
|
||||
|
||||
def popup_menu_selected_choice(self, window, choice):
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.create_task(self.select_category(choice))
|
||||
|
||||
def popup_menu_closing(self, window):
|
||||
pass
|
||||
|
||||
def cleanup(self):
|
||||
self.plugin_manager.cleanup()
|
||||
for plugin in self._columnwidget.get_children():
|
||||
|
|
@ -1081,7 +1186,7 @@ class PluginManagerSettingsWindow(popup.PopupWindow):
|
|||
ba.buttonwidget(parent=self._root_widget,
|
||||
position=(width * 0.125, pos),
|
||||
size=button_size,
|
||||
on_activate_call=self._open,
|
||||
on_activate_call=lambda: ba.open_url(GITHUB_REPO_LINK),
|
||||
textcolor=b_text_color,
|
||||
button_type='square',
|
||||
text_scale=1,
|
||||
|
|
@ -1094,9 +1199,6 @@ class PluginManagerSettingsWindow(popup.PopupWindow):
|
|||
play_sound()
|
||||
ba.containerwidget(edit=self._root_widget, transition='out_scale')
|
||||
|
||||
def _open(self) -> None:
|
||||
ba.open_url(GITHUB_REPO_LINK)
|
||||
|
||||
|
||||
class NewAllSettingsWindow(ba.Window):
|
||||
def __init__(self,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue