Add possibility to delete books which don't have a category

Orionik [09-11-22 - 19:08]
Add possibility to delete books which don't have a category
These books are saved entirely so they can be in a different language than the rest. I didn't add the possibility to remove book which have a category because they will be added back automatically upon next reload of the UI and they use text from the game so they are always in the right language.
Update Changelog
Filename
CHANGELOG
Librarian.lua
lang/en.lua
lang/fr.lua
diff --git a/CHANGELOG b/CHANGELOG
index 67acf05..51c9568 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,10 @@
 -------------------------------------------------------------------------------
 Librarian v3.0 2022-07-25
 -------------------------------------------------------------------------------
+3.4 2022-09-11
+- Add keybind in lore reader only when the book is recognized by Librarian (it avoids conflicting with other addon like TheLibrarium)
+- Add possibility to delete books which don't have a category
+
 3.3 2022-08-23
 - Updated API for Lost Depths (101035)
 - Widden "Found" column for 12Hour format
diff --git a/Librarian.lua b/Librarian.lua
index 83164c5..19126f9 100644
--- a/Librarian.lua
+++ b/Librarian.lua
@@ -23,6 +23,34 @@ local ENTRY_SORT_KEYS =
     ["wordCount"] = { tiebreaker = "title" }
 }

+ESO_Dialogs["LIBRARIAN_DELETE_BOOK"] =
+{
+    gamepadInfo =
+    {
+        dialogType = GAMEPAD_DIALOGS.BASIC,
+    },
+    title =
+    {
+        text = LIBRARIAN_DELETE_BOOK_PROMPT_TITLE,
+    },
+    mainText =
+    {
+        text = LIBRARIAN_DELETE_BOOK_PROMPT_MESSAGE,
+    },
+    buttons =
+    {
+        [1] =
+        {
+            text = SI_YES,
+            callback =  function(dialog) LIBRARIAN:RemoveBook(dialog.data.bookId) end,
+        },
+        [2] =
+        {
+            text = SI_NO,
+        }
+    }
+}
+
 function Librarian:New()
     return ZO_SortFilterList.New(self, LibrarianFrame)
 end
@@ -50,6 +78,8 @@ function Librarian:Initialize(...)
     if not self.globalSavedVars.books then self.globalSavedVars.books = {} end
     self.books = self.globalSavedVars.books

+    if not self.globalSavedVars.deletedBooks then self.globalSavedVars.deletedBooks = {} end
+
     if not self.localSavedVars.characterBooks then
         self.localSavedVars.characterBooks = {}
         self.localSavedVars.saveVersion = 2
@@ -57,6 +87,10 @@ function Librarian:Initialize(...)
     self.characterBooks = self.localSavedVars.characterBooks
     self.characterBooksCache = {}

+    for _, bookIdToDelete in ipairs(self.globalSavedVars.deletedBooks) do
+        self:RemoveCharacterBook(bookIdToDelete)
+    end
+
     self.searchBox = GetControl(LibrarianFrame, "SearchBox")
     self.searchBox:SetHandler("OnTextChanged", function() self:OnSearchTextChanged() end)
     self.search = ZO_StringSearch:New()
@@ -372,6 +406,18 @@ function Librarian:InitializeKeybindStripDescriptors()
                 LORE_LIBRARY:SetCollectionIdToSelect(collectionId)
                 MAIN_MENU_KEYBOARD:ShowScene("loreLibrary")
             end,
+        },
+        {
+            alignment = KEYBIND_STRIP_ALIGN_LEFT,
+            name = GetString(LIBRARIAN_DELETE_BOOK),
+            keybind = "UI_SHORTCUT_NEGATIVE",
+            visible = function()
+                return self.mouseOverRow and (not self.mouseOverRow.data.categoryIndex or not self.mouseOverRow.data.collectionIndex)
+            end,
+            callback = function()
+                self.potentialBookIdToDelete = self.mouseOverRow.data.bookId
+                ZO_Dialogs_ShowPlatformDialog("LIBRARIAN_DELETE_BOOK", {bookId = self.mouseOverRow.data.bookId}, {mainTextParams = {self.mouseOverRow.data.title}})
+            end,
         }
     }
 end
@@ -655,6 +701,13 @@ function Librarian:AddBookToGlobalSave(book)
     end

     table.insert(self.books, book)
+
+    for index, bookIdToDelete in ipairs(self.globalSavedVars.deletedBooks) do
+        if bookIdToDelete == book.bookId then
+            table.remove(self.globalSavedVars.deletedBooks, index)
+            break
+        end
+    end
 end

 function Librarian:AddBook(book, refreshDataRightAway)
@@ -700,6 +753,40 @@ function Librarian:AddBook(book, refreshDataRightAway)

 end

+function Librarian:RemoveBook(bookId)
+    for _, bookIdToDelete in ipairs(self.globalSavedVars.deletedBooks) do
+        if bookIdToDelete == bookId then
+            d("Couldn't delete book, it is already beeing deleted")
+            return
+        end
+    end
+
+    table.insert(self.globalSavedVars.deletedBooks, bookId)
+
+    for index ,book in ipairs(self.books) do
+        if book.bookId == bookId then
+            table.remove(self.books, index)
+            break
+        end
+    end
+
+    self.characterBooksCache[bookId] = nil
+    self:RemoveCharacterBook(bookId)
+
+    -- Clean the master list to be sure the entry is removed from the display as well
+    self.masterList = {}
+    self:RefreshAllData()
+end
+
+function Librarian:RemoveCharacterBook(bookId)
+    for index ,book in ipairs(self.characterBooks) do
+        if book.bookId == bookId then
+            table.remove(self.characterBooks, index)
+            break
+        end
+    end
+end
+
 function Librarian:AddUnreadBookInCollection(categoryIndex, collectionIndex)
     if not self.unreadPerCollections[categoryIndex] then self.unreadPerCollections[categoryIndex] = {} end
     if not self.unreadPerCollections[categoryIndex][collectionIndex] then self.unreadPerCollections[categoryIndex][collectionIndex] = 0 end
diff --git a/lang/en.lua b/lang/en.lua
index 87bd1aa..18c7e6d 100644
--- a/lang/en.lua
+++ b/lang/en.lua
@@ -25,6 +25,9 @@ local strings = {
     LIBRARIAN_RELOAD_REMINDER = "ReloadUI suggested to update Librarian database.",
     LIBRARIAN_BACKUP_REMINDER = "Remember to backup your Librarian SavedVariables regularly.  Look up Librarian on ESOUI for instructions.",
     LIBRARIAN_COULD_NOT_READ = "The current character doesn't know this book, you can't read it",
+    LIBRARIAN_DELETE_BOOK = "Delete Book",
+    LIBRARIAN_DELETE_BOOK_PROMPT_TITLE = "Delete Book",
+    LIBRARIAN_DELETE_BOOK_PROMPT_MESSAGE = "Are you sure you want to delete <<1>> ?\nTo have this book back in Librarian, you will have to find this book in the world and open it again.",

     -- Settings
     LIBRARIAN_SETTINGS_DISPLAY_NAME = "Librarian Book Manager",
diff --git a/lang/fr.lua b/lang/fr.lua
index 3e0113d..7d58c41 100644
--- a/lang/fr.lua
+++ b/lang/fr.lua
@@ -1,55 +1,58 @@
-SafeAddString(SI_BINDING_NAME_LIBRARIAN_TOGGLE_LIBRARIAN,			"Afficher/Masquer Librarian", 1)
-SafeAddString(SI_BINDING_NAME_LIBRARIAN_RELOAD_UI,					"Reload UI", 1)
+SafeAddString(SI_BINDING_NAME_LIBRARIAN_TOGGLE_LIBRARIAN,           "Afficher/Masquer Librarian", 1)
+SafeAddString(SI_BINDING_NAME_LIBRARIAN_RELOAD_UI,                  "Reload UI", 1)

-SafeAddString(LIBRARIAN_WINDOW_TITLE_LIBRARIAN,						"Librarian", 1)
-SafeAddString(LIBRARIAN_SORT_TYPE_UNREAD,							"Lu", 1)
-SafeAddString(LIBRARIAN_SORT_TYPE_FOUND,							"Trouvé", 1)
-SafeAddString(LIBRARIAN_SORT_TYPE_TITLE,							"Titre", 1)
-SafeAddString(LIBRARIAN_SORT_TYPE_CATEGORY,							"Catégorie", 1)
-SafeAddString(LIBRARIAN_SORT_TYPE_WORD_COUNT,						"Nb Mots", 1)
-SafeAddString(LIBRARIAN_MARK_UNREAD,								"Marquer comme lu", 1)
-SafeAddString(LIBRARIAN_MARK_READ,									"Marquer comme non lu", 1)
-SafeAddString(LIBRARIAN_BOOK_COUNT,									"%d Livres", 1)
-SafeAddString(LIBRARIAN_UNREAD_COUNT,								"%s (%d Non lu)", 1)
-SafeAddString(LIBRARIAN_SHOW_ALL_BOOKS,								"Montrer les livres pour tous les personnages", 1)
-SafeAddString(LIBRARIAN_NEW_BOOK_FOUND,								"Livre ajouté à Librarian", 1)
-SafeAddString(LIBRARIAN_NEW_BOOK_FOUND_WITH_TITLE,					"Livre ajouté à Librarian: %s", 1)
-SafeAddString(LIBRARIAN_FULLTEXT_SEARCH,							"Recherche titre + contenu:", 1)
-SafeAddString(LIBRARIAN_TITLE_SEARCH,							    "Recherche titre seulement:", 1)
-SafeAddString(LIBRARIAN_SEARCH_HINT,								"Texte à rechercher.", 1)
-SafeAddString(LIBRARIAN_NO_CATEGORY,								"Pas de catégorie", 1)
-SafeAddString(LIBRARIAN_GO_TO_CATEGORY,								"Ouvrir la catégorie", 1)
-SafeAddString(LIBRARIAN_RELOAD_REMINDER,							"ReloadUI conseillé pour mettre à jour les données de Librarian.", 1)
-SafeAddString(LIBRARIAN_BACKUP_REMINDER,							"Pensez à sauvegader les SaveVariables de Librarian régulièrement. Cherchez 'Librarian' sur ESOUI pour plus d'explications (en anglais).", 1)
-SafeAddString(LIBRARIAN_COULD_NOT_READ,							    "Ce personnage ne connait pas ce livre, impossible de le lire.", 1)
+SafeAddString(LIBRARIAN_WINDOW_TITLE_LIBRARIAN,                     "Librarian", 1)
+SafeAddString(LIBRARIAN_SORT_TYPE_UNREAD,                           "Lu", 1)
+SafeAddString(LIBRARIAN_SORT_TYPE_FOUND,                            "Trouvé", 1)
+SafeAddString(LIBRARIAN_SORT_TYPE_TITLE,                            "Titre", 1)
+SafeAddString(LIBRARIAN_SORT_TYPE_CATEGORY,                         "Catégorie", 1)
+SafeAddString(LIBRARIAN_SORT_TYPE_WORD_COUNT,                       "Nb Mots", 1)
+SafeAddString(LIBRARIAN_MARK_UNREAD,                                "Marquer comme lu", 1)
+SafeAddString(LIBRARIAN_MARK_READ,                                  "Marquer comme non lu", 1)
+SafeAddString(LIBRARIAN_BOOK_COUNT,                                 "%d Livres", 1)
+SafeAddString(LIBRARIAN_UNREAD_COUNT,                               "%s (%d Non lu)", 1)
+SafeAddString(LIBRARIAN_SHOW_ALL_BOOKS,                             "Montrer les livres pour tous les personnages", 1)
+SafeAddString(LIBRARIAN_NEW_BOOK_FOUND,                             "Livre ajouté à Librarian", 1)
+SafeAddString(LIBRARIAN_NEW_BOOK_FOUND_WITH_TITLE,                  "Livre ajouté à Librarian: %s", 1)
+SafeAddString(LIBRARIAN_FULLTEXT_SEARCH,                            "Recherche titre + contenu:", 1)
+SafeAddString(LIBRARIAN_TITLE_SEARCH,                               "Recherche titre seulement:", 1)
+SafeAddString(LIBRARIAN_SEARCH_HINT,                                "Texte à rechercher.", 1)
+SafeAddString(LIBRARIAN_NO_CATEGORY,                                "Pas de catégorie", 1)
+SafeAddString(LIBRARIAN_GO_TO_CATEGORY,                             "Ouvrir la catégorie", 1)
+SafeAddString(LIBRARIAN_RELOAD_REMINDER,                            "ReloadUI conseillé pour mettre à jour les données de Librarian.", 1)
+SafeAddString(LIBRARIAN_BACKUP_REMINDER,                            "Pensez à sauvegader les SaveVariables de Librarian régulièrement. Cherchez 'Librarian' sur ESOUI pour plus d'explications (en anglais).", 1)
+SafeAddString(LIBRARIAN_COULD_NOT_READ,                             "Ce personnage ne connait pas ce livre, impossible de le lire.", 1)
+SafeAddString(LIBRARIAN_DELETE_BOOK,                                "Supprimer le livre", 1)
+SafeAddString(LIBRARIAN_DELETE_BOOK_PROMPT_TITLE,                   "Supprimer un livre", 1)
+SafeAddString(LIBRARIAN_DELETE_BOOK_PROMPT_MESSAGE,                 "Etes-vous sûr de vouloir supprimer <<1>> ?\nPour ré-afficher ce livre dans Librarian, vous devrez chercher le livre dans le monde et l'ouvrir.", 1)

-SafeAddString(LIBRARIAN_SETTINGS_DISPLAY_NAME,						"Librarian (Gestionaire de livres)", 1)
-SafeAddString(LIBRARIAN_SETTINGS_TIME,								"Format d'heure", 1)
-SafeAddString(LIBRARIAN_SETTINGS_TIME_TOOLTIP,						"Quel format d'heure préférez-vous ?", 1)
-SafeAddString(LIBRARIAN_SETTINGS_ALERT,								"Options d'alert", 1)
-SafeAddString(LIBRARIAN_SETTINGS_ALERT_TOOLTIP,						"Comment souhaitez-vous être alerté ?", 1)
-SafeAddString(LIBRARIAN_SETTINGS_RELOADUI_REMINDER,					"Rappel 'ReloadUI' après", 1)
-SafeAddString(LIBRARIAN_SETTINGS_RELOADUI_REMINDER_TOOLTIP,			"Rappel pour lancer la commande /reloadui après que ce nombre de livre ait été découvert.", 1)
-SafeAddString(LIBRARIAN_SETTINGS_SHOW_HIDDEN_BOOK, 					"Montrer les livres cachés", 1)
-SafeAddString(LIBRARIAN_SETTINGS_SHOW_HIDDEN_BOOK_TOOLTIP, 			"TESO cache certaines collections de livres dans la bibliothèque. Par example les livres contenant le motif complet (au lieu des 14 pages) font parti de ces livres cachés. Donc, si vous souhaitez que le nombre de livre affiché dans Librarian corresponde à celui de la Bibliothèque, vous devez décocher cette case.", 1)
-SafeAddString(LIBRARIAN_SETTINGS_UNREAD_INDICATOR_READER,			"Icône 'Non-lu' (Liseuse)", 1)
-SafeAddString(LIBRARIAN_SETTINGS_UNREAD_INDICATOR_READER_TOOLTIP,	"Affiche une icone 'Non-lu' à côté du titre lors de la lecture d'un livre.", 1)
-SafeAddString(LIBRARIAN_SETTINGS_ICON_TRANSPARENCY,					"Transparence de l'icone", 1)
-SafeAddString(LIBRARIAN_SETTINGS_ICON_TRANSPARENCY_TOOLTIP,			"A quel point souhaitez-vous que l'icone 'Non-lu' soit transparente (100 complètement visible, 0 complètement transparente).", 1)
-SafeAddString(LIBRARIAN_SETTINGS_UNREAD_INDICATOR_LIBRARY,			"Icône 'Non-lu' (Bibliothèque)", 1)
-SafeAddString(LIBRARIAN_SETTINGS_UNREAD_INDICATOR_LIBRARY_TOOLTIP,	"Affiche une icone 'Non-lu' dans la Bibliothèque à côté des collections contenant au moins un livre 'Non-lu' et à côté de chaque livre 'Non-lu'.", 1)
-SafeAddString(LIBRARIAN_SETTINGS_CHARACTER_SPIN,					"Tourner le personnage", 1)
-SafeAddString(LIBRARIAN_SETTINGS_CHARACTER_SPIN_TOOLTIP,			"Tourne le personnage pour qu'il soit face à la camera quand Librarian est ouvert.", 1)
-SafeAddString(LIBRARIAN_SETTINGS_IMPORT,							"Importer de la Bibliothèque", 1)
-SafeAddString(LIBRARIAN_SETTINGS_IMPORT_TOOLTIP,					"Importer tous les livres de la Bibliothèque.  Fonctionne avec tous les livres lorsque la mémoire eidétique est débloquée.", 1)
+SafeAddString(LIBRARIAN_SETTINGS_DISPLAY_NAME,                      "Librarian (Gestionaire de livres)", 1)
+SafeAddString(LIBRARIAN_SETTINGS_TIME,                              "Format d'heure", 1)
+SafeAddString(LIBRARIAN_SETTINGS_TIME_TOOLTIP,                      "Quel format d'heure préférez-vous ?", 1)
+SafeAddString(LIBRARIAN_SETTINGS_ALERT,                             "Options d'alert", 1)
+SafeAddString(LIBRARIAN_SETTINGS_ALERT_TOOLTIP,                     "Comment souhaitez-vous être alerté ?", 1)
+SafeAddString(LIBRARIAN_SETTINGS_RELOADUI_REMINDER,                 "Rappel 'ReloadUI' après", 1)
+SafeAddString(LIBRARIAN_SETTINGS_RELOADUI_REMINDER_TOOLTIP,         "Rappel pour lancer la commande /reloadui après que ce nombre de livre ait été découvert.", 1)
+SafeAddString(LIBRARIAN_SETTINGS_SHOW_HIDDEN_BOOK,                  "Montrer les livres cachés", 1)
+SafeAddString(LIBRARIAN_SETTINGS_SHOW_HIDDEN_BOOK_TOOLTIP,          "TESO cache certaines collections de livres dans la bibliothèque. Par example les livres contenant le motif complet (au lieu des 14 pages) font parti de ces livres cachés. Donc, si vous souhaitez que le nombre de livre affiché dans Librarian corresponde à celui de la Bibliothèque, vous devez décocher cette case.", 1)
+SafeAddString(LIBRARIAN_SETTINGS_UNREAD_INDICATOR_READER,           "Icône 'Non-lu' (Liseuse)", 1)
+SafeAddString(LIBRARIAN_SETTINGS_UNREAD_INDICATOR_READER_TOOLTIP,   "Affiche une icone 'Non-lu' à côté du titre lors de la lecture d'un livre.", 1)
+SafeAddString(LIBRARIAN_SETTINGS_ICON_TRANSPARENCY,                 "Transparence de l'icone", 1)
+SafeAddString(LIBRARIAN_SETTINGS_ICON_TRANSPARENCY_TOOLTIP,         "A quel point souhaitez-vous que l'icone 'Non-lu' soit transparente (100 complètement visible, 0 complètement transparente).", 1)
+SafeAddString(LIBRARIAN_SETTINGS_UNREAD_INDICATOR_LIBRARY,          "Icône 'Non-lu' (Bibliothèque)", 1)
+SafeAddString(LIBRARIAN_SETTINGS_UNREAD_INDICATOR_LIBRARY_TOOLTIP,  "Affiche une icone 'Non-lu' dans la Bibliothèque à côté des collections contenant au moins un livre 'Non-lu' et à côté de chaque livre 'Non-lu'.", 1)
+SafeAddString(LIBRARIAN_SETTINGS_CHARACTER_SPIN,                    "Tourner le personnage", 1)
+SafeAddString(LIBRARIAN_SETTINGS_CHARACTER_SPIN_TOOLTIP,            "Tourne le personnage pour qu'il soit face à la camera quand Librarian est ouvert.", 1)
+SafeAddString(LIBRARIAN_SETTINGS_IMPORT,                            "Importer de la Bibliothèque", 1)
+SafeAddString(LIBRARIAN_SETTINGS_IMPORT_TOOLTIP,                    "Importer tous les livres de la Bibliothèque.  Fonctionne avec tous les livres lorsque la mémoire eidétique est débloquée.", 1)

-SafeAddString(LIBRARIAN_SETTINGS_TIME_12,							"12 heures", 1)
-SafeAddString(LIBRARIAN_SETTINGS_TIME_24,							"24 heures", 1)
-SafeAddString(LIBRARIAN_SETTINGS_ALERT_NONE,						"Aucune alerte", 1)
-SafeAddString(LIBRARIAN_SETTINGS_ALERT_CHAT,						"Chat seulement", 1)
-SafeAddString(LIBRARIAN_SETTINGS_ALERT_NOTIFICATION,				"Notification seulement", 1)
-SafeAddString(LIBRARIAN_SETTINGS_ALERT_BOTH,						"Les deux", 1)
-SafeAddString(LIBRARIAN_SETTINGS_RELOAD_REMNDER_NEVER,				"Jamais", 1)
-SafeAddString(LIBRARIAN_SETTINGS_RELOAD_REMNDER_1,					"1 nouveau livre", 1)
-SafeAddString(LIBRARIAN_SETTINGS_RELOAD_REMNDER_5,					"5 nouveaux livres", 1)
-SafeAddString(LIBRARIAN_SETTINGS_RELOAD_REMNDER_10,					"10 nouveaux livres", 1)
+SafeAddString(LIBRARIAN_SETTINGS_TIME_12,                           "12 heures", 1)
+SafeAddString(LIBRARIAN_SETTINGS_TIME_24,                           "24 heures", 1)
+SafeAddString(LIBRARIAN_SETTINGS_ALERT_NONE,                        "Aucune alerte", 1)
+SafeAddString(LIBRARIAN_SETTINGS_ALERT_CHAT,                        "Chat seulement", 1)
+SafeAddString(LIBRARIAN_SETTINGS_ALERT_NOTIFICATION,                "Notification seulement", 1)
+SafeAddString(LIBRARIAN_SETTINGS_ALERT_BOTH,                        "Les deux", 1)
+SafeAddString(LIBRARIAN_SETTINGS_RELOAD_REMNDER_NEVER,              "Jamais", 1)
+SafeAddString(LIBRARIAN_SETTINGS_RELOAD_REMNDER_1,                  "1 nouveau livre", 1)
+SafeAddString(LIBRARIAN_SETTINGS_RELOAD_REMNDER_5,                  "5 nouveaux livres", 1)
+SafeAddString(LIBRARIAN_SETTINGS_RELOAD_REMNDER_10,                 "10 nouveaux livres", 1)