diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f7d132..6f29705 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,11 @@ * New 'detailed INF' report. This is optional and is off by default, but when enabled gives a detailed breakdown of the number of missions completed at each +INF level. For example: `INF +19 (โž‹ x 4 โžŒ x 2 โžŽ x 1)` means you completed 4 missions awarding ++, 2 mission awarding +++ and 1 mission awarding +++++. Manually tallied INF is simply added or removed from the overall total. * When secondary INF reporting is switched on, now indicate which INF is primary `๐Ÿ…Ÿ` and which is secondary `๐Ÿ…ข`. This can also combine with detailed INF reporting to give a full breakdown of primary and secondary INF. * New 'detailed Trade' checkbox, which is on by default and when enabled shows the full trade breakdown into brackets ๐Ÿ†‰ | ๐Ÿ…ป | ๐Ÿ…ผ | ๐Ÿ…ท, when disabled all brackets are combined into simple totals for trade purchase and trade profit. +* When multiple CMDRs are selected in the CMDR window, 'Post to Discord' now posts a concise table containing all the CMDRs in the list, with Inara and Inara squadron links where available. With a single CMDR selected, posting is exactly the same as it was. ### Changes: -* Activity windows (latest Tally / previous Tally) will now remember their positions and sizes. +* Activity windows (latest Tally / previous Tally) will now remember their positions and sizes within a game session. * Re-opening an already open activity window (latest Tally / previous Tally) will no longer open two copies of the same window. Instead, the old one will be closed and a new fresh window with latest data opened at the same position and size on screen. diff --git a/bgstally/windows/cmdrs.py b/bgstally/windows/cmdrs.py index f75f2f9..cd7e4e1 100644 --- a/bgstally/windows/cmdrs.py +++ b/bgstally/windows/cmdrs.py @@ -21,6 +21,7 @@ def __init__(self, bgstally): self.bgstally = bgstally self.selected_cmdr:dict = None + self.selected_items:list = None self.target_data:list = None self.toplevel:tk.Toplevel = None @@ -59,6 +60,7 @@ def show(self): self.target_data = self.bgstally.target_log.get_targetlog() treeview = TreeviewPlus(list_frame, columns=[d['title'] for d in column_info], show="headings", callback=self._cmdr_selected, datetime_format=DATETIME_FORMAT_CMDRLIST) + treeview.bind('<>', partial(self._cmdr_selection_changed, treeview)) vsb = tk.Scrollbar(list_frame, orient=tk.VERTICAL, command=treeview.yview) vsb.pack(fill=tk.Y, side=tk.RIGHT) treeview.configure(yscrollcommand=vsb.set) @@ -96,11 +98,11 @@ def show(self): target.get('Notes', "Scanned")] treeview.insert("", 'end', values=target_values, iid=target.get('index')) - self.post_button = tk.Button(buttons_frame, text="Post to Discord", command=partial(self._post_to_discord)) + self.post_button = tk.Button(buttons_frame, text="Post CMDR to Discord", command=partial(self._post_to_discord)) self.post_button.pack(side=tk.RIGHT, padx=5, pady=5) self.post_button['state'] = tk.DISABLED - self.delete_button = tk.Button(buttons_frame, text="Delete", bg="red", fg="white", command=partial(self._delete_selected, treeview)) + self.delete_button = tk.Button(buttons_frame, text="Delete Selected", bg="red", fg="white", command=partial(self._delete_selected, treeview)) self.delete_button.pack(side=tk.RIGHT, padx=5, pady=5) self.delete_button['state'] = tk.DISABLED @@ -118,14 +120,6 @@ def _cmdr_selected(self, values, column, treeview:TreeviewPlus, iid:str): # Fetch the info for this CMDR. iid is the index into the original (unsorted) CMDR list. self.selected_cmdr = self.target_data[int(iid)] - if not self.selected_cmdr: - self.post_button['state'] = tk.DISABLED - self.delete_button['state'] = tk.DISABLED - return - elif self.bgstally.discord.valid_webhook_available(DiscordChannel.CMDR_INFORMATION): - self.post_button['state'] = tk.NORMAL - self.delete_button['state'] = tk.NORMAL - if 'TargetName' in self.selected_cmdr: self.cmdr_details_name.config(text = self.selected_cmdr.get('TargetName')) if 'inaraURL' in self.selected_cmdr: self.cmdr_details_name_inara.configure(text = "Inara Info Available โคด", url = self.selected_cmdr.get('inaraURL')) if 'squadron' in self.selected_cmdr: @@ -137,6 +131,30 @@ def _cmdr_selected(self, values, column, treeview:TreeviewPlus, iid:str): if 'Notes' in self.selected_cmdr: self.cmdr_details_interaction.config(text = self.selected_cmdr.get('Notes')) + def _cmdr_selection_changed(self, treeview:TreeviewPlus, *args): + """ + The selected CMDRs have changed in the list. Called on any change, so there could be nothing selected, one CMDR selected + or multiple CMDRs. + + Args: + treeview (TreeviewPlus): The TreeViewPlus object + """ + self.selected_items = treeview.selection() + + if len(self.selected_items) == 1 and self.bgstally.discord.valid_webhook_available(DiscordChannel.CMDR_INFORMATION): + self.post_button.configure(text = "Post CMDR to Discord") + self.post_button['state'] = tk.NORMAL + self.delete_button['state'] = tk.NORMAL + elif len(self.selected_items) > 1 and self.bgstally.discord.valid_webhook_available(DiscordChannel.CMDR_INFORMATION): + self.post_button.configure(text = "Post CMDR List to Discord") + self.post_button['state'] = tk.NORMAL + self.delete_button['state'] = tk.NORMAL + else: + self.post_button.configure(text = "Post CMDR to Discord") + self.post_button['state'] = tk.DISABLED + self.delete_button['state'] = tk.DISABLED + + def _delete_selected(self, treeview:TreeviewPlus): """ Delete the currently selected CMDRs @@ -144,13 +162,26 @@ def _delete_selected(self, treeview:TreeviewPlus): selected_items:list = treeview.selection() for selected_iid in selected_items: for i in range(len(self.target_data)): - if self.target_data[i]['iid'] == selected_iid: + if int(self.target_data[i]['index']) == int(selected_iid): self.target_data.pop(i) # Remove the corresponding item break - treeview.delete(selected_iid) + treeview.delete(int(selected_iid)) + + self.selected_cmdr = None + self._cmdr_selection_changed(treeview) def _post_to_discord(self): + """ + Post the current selected CMDR or multiple CMDR details to discord + """ + if len(self.selected_items) == 1 and self.bgstally.discord.valid_webhook_available(DiscordChannel.CMDR_INFORMATION): + self._post_single_cmdr_to_discord() + elif len(self.selected_items) > 1 and self.bgstally.discord.valid_webhook_available(DiscordChannel.CMDR_INFORMATION): + self._post_multiple_CMDRs_to_discord() + + + def _post_single_cmdr_to_discord(self): """ Post the current selected cmdr details to discord """ @@ -224,3 +255,34 @@ def _post_to_discord(self): description = f"```ansi\n{description}\n```" self.bgstally.discord.post_embed(f"CMDR {self.selected_cmdr.get('TargetName')}", description, embed_fields, None, DiscordChannel.CMDR_INFORMATION, None) + + + def _post_multiple_CMDRs_to_discord(self): + """ + Post the currently selected list of CMDRs to discord + """ + text:str = "" + + for selected_iid in self.selected_items: + if len(text) > 1500: + text += "[...]" + break + + for cmdr in self.target_data: + if int(cmdr['index']) == int(selected_iid): + text += f"{datetime.strptime(cmdr.get('Timestamp'), DATETIME_FORMAT_JOURNAL).strftime(DATETIME_FORMAT_CMDRLIST)}: " + + if 'inaraURL' in cmdr: + text += f" - [{cmdr.get('TargetName')}]({cmdr.get('inaraURL')})" + else: + text += f" - {cmdr.get('TargetName')}" + + text += f" - [{cmdr.get('System')}](https://inara.cz/elite/starsystem/?search={cmdr.get('System')}) - {cmdr.get('Ship')}" + + if 'squadron' in cmdr: + squadron_info = cmdr.get('squadron') + if 'squadronName' in squadron_info and 'inaraURL' in squadron_info: + text += f" - [{squadron_info.get('squadronName')}]({squadron_info.get('inaraURL')})" + text += "\n" + + self.bgstally.discord.post_plaintext(text, None, DiscordChannel.CMDR_INFORMATION, None)