Add UI for adding 3rd party plugins (tested for UIScale.LARGE rn)

This commit is contained in:
Rikko 2022-08-11 06:34:17 +05:30
parent 5a2144fa88
commit 607663d2ac

View file

@ -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,