diff --git a/Contents/mods/CommunityAPI/media/lua/client/CommunityAPI.lua b/Contents/mods/CommunityAPI/media/lua/client/CommunityAPI.lua index bbf3e78..bc5b118 100644 --- a/Contents/mods/CommunityAPI/media/lua/client/CommunityAPI.lua +++ b/Contents/mods/CommunityAPI/media/lua/client/CommunityAPI.lua @@ -3,6 +3,7 @@ require("CommunityAPIShared") CommunityAPI.Client = { ItemTooltip = require("ItemTooltipAPI/ItemTooltipAPIClient"), Light = require("LightAPI/LightAPIClient"), + ModNews = require("ModNewsAPI/ModNewsAPIClient"), ModSetting = require("ModSettingAPI/ModSettingAPIClient"), Spawner = require("SpawnerAPI/SpawnerAPIClient"), WorldSound = require("WorldSoundAPI/WorldSoundAPIClient"), diff --git a/Contents/mods/CommunityAPI/media/lua/client/ModNewsAPI/ModNewsAPIClient.lua b/Contents/mods/CommunityAPI/media/lua/client/ModNewsAPI/ModNewsAPIClient.lua new file mode 100644 index 0000000..4f3c1cd --- /dev/null +++ b/Contents/mods/CommunityAPI/media/lua/client/ModNewsAPI/ModNewsAPIClient.lua @@ -0,0 +1,85 @@ +local JsonAPI = require("CommunityAPI/JsonUtils") + +---@class ModNewsAPI +local ModNewsAPI = {} +local Data = {} + +--- Load the data +local function ModNewsAPILoadData() + local fileReader = getFileReader("CAPI_modNewsData.txt", true) + if not fileReader then return end + local line = fileReader:readLine() + local modNewsData = nil + if line ~= nil then + modNewsData = JsonAPI.Decode(line) + end + fileReader:close() + + if modNewsData ~= nil and type(modNewsData) == "table" then + for modID, modData in pairs(modNewsData) do + for articleName, data in pairs(modData) do + if Data[modID] ~= nil and Data[modID][articleName] ~= nil then + if data.isViewed and data.lastUpdateDate == Data[modID][articleName].lastUpdateDate then + Data[modID][articleName].isViewed = true + end + end + end + end + end +end +Events.OnGameBoot.Add(ModNewsAPILoadData) + +--- Add a new Article for your mod +---@param modID string The mod ID +---@param articleName string The article Name +---@param articleTextName string Article text name from Translate +---@param lastUpdateDate string String with date of last update. If you changed article and want to notify that article updated - change this param +---@return nil +function ModNewsAPI.AddArticle(modID, articleName, articleTextName, lastUpdateDate) + if Data[modID] == nil then + Data[modID] = {} + end + Data[modID][articleName] = {} + Data[modID][articleName].modID = modID + Data[modID][articleName].articleName = articleName + Data[modID][articleName].articleTextName = articleTextName + Data[modID][articleName].lastUpdateDate = lastUpdateDate + Data[modID][articleName].isViewed = false +end + +--- Get all Data (readonly) +---@return table +function ModNewsAPI.GetAll() + return copyTable(Data) +end + +--- Get a specific mod article (readonly) +---@param modID string The mod ID +---@param articleName string The article Name +---@return table +function ModNewsAPI.GetArticle(modID, articleName) + if Data[modID] and Data[modID][articleName] then + return copyTable(Data[modID][articleName]) + end +end + +--- Check if an article is viewed already +---@param modID string The mod ID +---@param articleName string The article Name +---@return boolean True if viewed +function ModNewsAPI.GetArticleIsViewed(modID, articleName) + if Data[modID] and Data[modID][articleName] then + return Data[modID][articleName].isViewed + end +end + +--- Set an article as viewed +---@param modID string The mod ID +---@param articleName string The article Name +function ModNewsAPI.SetArticleAsViewed(modID, articleName) + if Data[modID] and Data[modID][articleName] then + Data[modID][articleName].isViewed = true + end +end + +return ModNewsAPI \ No newline at end of file diff --git a/Contents/mods/CommunityAPI/media/lua/client/ModNewsAPI/ModNewsButton.lua b/Contents/mods/CommunityAPI/media/lua/client/ModNewsAPI/ModNewsButton.lua new file mode 100644 index 0000000..af2a59b --- /dev/null +++ b/Contents/mods/CommunityAPI/media/lua/client/ModNewsAPI/ModNewsButton.lua @@ -0,0 +1,70 @@ +require("CommunityAPI") +local ModNewsAPI = CommunityAPI.Client.ModNews +local ModNewsPanel = require("ModNewsAPI/ModNewsPanel") + +local FONT_HGT_MEDIUM = getTextManager():getFontHeight(UIFont.Medium) + +local function renderModNewsButton(self) + ISButton.render(self) + + local Data = ModNewsAPI.GetAll() + local isNewArticles = false + for _, modData in pairs(Data) do + for _, articleData in pairs(modData) do + if articleData.isViewed == false then + isNewArticles = true + end + end + end + + if isNewArticles then + local x = - self.notifyIcon:getWidthOrig()/2 + self.width + local y = - self.notifyIcon:getHeightOrig()/2 - 2 + self:drawTexture(self.notifyIcon, x, y, 1, 1, 1, 1) + end +end + +local function onClickModNews(self) + local w = self.width * 0.8 + local h = self.height * 0.8 + local newsPanel = ModNewsPanel:new((self.width - w)/2, (self.height - h)/2, w, h) + newsPanel.backgroundColor = {r=0, g=0, b=0, a=0.95} + newsPanel.borderColor = {r=1, g=1, b=1, a=0.5} + newsPanel:initialise() + newsPanel:instantiate() + newsPanel:setCapture(true) + newsPanel:setAlwaysOnTop(true) + newsPanel:setAnchorRight(true) + newsPanel:setAnchorLeft(true) + newsPanel:setAnchorBottom(true) + newsPanel:setAnchorTop(true) + newsPanel:addToUIManager() +end + +-- Hook +local defaultMainScreen_instantiate = MainScreen.instantiate +function MainScreen:instantiate() + defaultMainScreen_instantiate(self) + + self.modNewsDetail = ISButton:new(self.width - 40 - 400, self.height - FONT_HGT_MEDIUM - 20, 120, FONT_HGT_MEDIUM + 1 * 2, getText("UI_modNews_button"), self, onClickModNews) + self.modNewsDetail.font = UIFont.Medium + self.modNewsDetail:initialise() + self.modNewsDetail.borderColor = {r=1, g=1, b=1, a=0.7} + self.modNewsDetail.textColor = {r=1, g=1, b=1, a=0.7} + self:addChild(self.modNewsDetail) + self.modNewsDetail:setAnchorLeft(false) + self.modNewsDetail:setAnchorTop(false) + self.modNewsDetail:setAnchorRight(true) + self.modNewsDetail:setAnchorBottom(true) + self.modNewsDetail.notifyIcon = getTexture("media/ui/ModNews/notifyIcon.png") + self.modNewsDetail.render = renderModNewsButton +end + +-- Hook +local defaultMainScreen_setBottomPanelVisible = MainScreen.setBottomPanelVisible +function MainScreen:setBottomPanelVisible(visible) + defaultMainScreen_setBottomPanelVisible(self, visible) + if self.parent and self.parent.modNewsDetail then + self.parent.modNewsDetail:setVisible(visible) + end +end \ No newline at end of file diff --git a/Contents/mods/CommunityAPI/media/lua/client/ModNewsAPI/ModNewsPanel.lua b/Contents/mods/CommunityAPI/media/lua/client/ModNewsAPI/ModNewsPanel.lua new file mode 100644 index 0000000..246276f --- /dev/null +++ b/Contents/mods/CommunityAPI/media/lua/client/ModNewsAPI/ModNewsPanel.lua @@ -0,0 +1,183 @@ +require("CommunityAPI") +local ModNewsAPI = CommunityAPI.Client.ModNews +local JsonAPI = CommunityAPI.Utils.Json + +local ModNewsPanel = ISPanelJoypad:derive("ModNewsPanel") + +local FONT_HGT_SMALL = getTextManager():getFontHeight(UIFont.Small) +local FONT_HGT_MEDIUM = getTextManager():getFontHeight(UIFont.Medium) + +function ModNewsPanel:createChildren() + self.modListBox = ISScrollingListBox:new(25, 50, self.width*0.2, self.height - 100) + self.modListBox:initialise() + self.modListBox:instantiate() + self.modListBox:setFont(UIFont.Medium, 2) + self.modListBox:setAnchorLeft(true) + self.modListBox:setAnchorRight(true) + self.modListBox:setAnchorTop(true) + self.modListBox:setAnchorBottom(true) + self.modListBox.doDrawItem = self.modListBoxItemDraw + self.modListBox.drawBorder = true + self.modListBox:setOnMouseDownFunction(self, self.onModListClick) + self:addChild(self.modListBox) + + local lWid = getTextManager():MeasureStringX(UIFont.Medium, getText("UI_NewGame_Mods")) + self.modsLabel = ISLabel:new(25 + self.modListBox.width/2 - lWid/2, 16, FONT_HGT_MEDIUM, getText("UI_NewGame_Mods"), 1, 1, 1, 1, UIFont.Medium, true) + self.modsLabel:initialise() + self.modsLabel:instantiate() + self:addChild(self.modsLabel) + + self.modArticleList = ISScrollingListBox:new(self.modListBox:getRight() + 25, 50, self.width*0.2, self.height - 100) + self.modArticleList:initialise() + self.modArticleList:instantiate() + self.modArticleList:setFont(UIFont.Medium, 2) + self.modArticleList:setAnchorLeft(true) + self.modArticleList:setAnchorRight(true) + self.modArticleList:setAnchorTop(true) + self.modArticleList:setAnchorBottom(true) + self.modArticleList.doDrawItem = self.modArticleItemDraw + self.modArticleList.drawBorder = true + self.modArticleList:setOnMouseDownFunction(self, self.onArcticleListClick) + self:addChild(self.modArticleList) + + lWid = getTextManager():MeasureStringX(UIFont.Medium, getText("UI_modNews_articleLabel")) + self.articleLabel = ISLabel:new(self.modArticleList:getX() + self.modArticleList.width/2 - lWid/2, 16, FONT_HGT_MEDIUM, getText("UI_modNews_articleLabel"), 1, 1, 1, 1, UIFont.Medium, true) + self.articleLabel:initialise() + self.articleLabel:instantiate() + self:addChild(self.articleLabel) + + local buttonHgt = FONT_HGT_SMALL + 3 * 2 + self.backButton = ISButton:new(16, self.height - 10 - buttonHgt, 100, buttonHgt, getText("UI_btn_back"), self, self.onOptionMouseDown) + self.backButton.internal = "BACK" + self.backButton:initialise() + self.backButton:instantiate() + self.backButton:setAnchorLeft(true) + self.backButton:setAnchorTop(false) + self.backButton:setAnchorBottom(true) + self.backButton.borderColor = {r=1, g=1, b=1, a=0.1} + self:addChild(self.backButton) + + self.articleText = ISRichTextPanel:new(self.modArticleList:getRight() + 50, 0, self.width - self.modArticleList:getRight() - 50, self.height) + self.articleText.marginRight = self.articleText.marginLeft + self.articleText:initialise() + self:addChild(self.articleText) + self.articleText:addScrollBars() + + self.articleText.background = false + self.articleText.clip = true + self.articleText.autosetheight = false + self.articleText.text = "" + self.articleText:paginate() + + self:populateModList() +end + +function ModNewsPanel:onModListClick() + self:populateArticleList() +end + +function ModNewsPanel:onArcticleListClick() + local item = self.modArticleList.items[self.modArticleList.selected].item + self:updateSettingView(item) + ModNewsAPI.SetArticleAsViewed(item.modID, item.articleName) +end + +function ModNewsPanel:updateSettingView(item) + self.articleText.text = getText(item.articleTextName) + self.articleText:paginate() +end + +function ModNewsPanel:populateArticleList() + local item = self.modListBox.items[self.modListBox.selected].item + self.modArticleList:clear() + + for articleName, data in pairs(item) do + self.modArticleList:addItem(articleName, data) + end +end + +function ModNewsPanel:populateModList() + self.modListBox:clear() + + local Data = ModNewsAPI.GetAll() + for modID, modArticleData in pairs(Data) do + local modInfo = getModInfoByID(modID) + if modInfo == nil then + self.modListBox:addItem("IncorrectModID - " .. modID, modArticleData) + else + self.modListBox:addItem(modInfo:getName(), modArticleData) + end + end +end + +function ModNewsPanel:modListBoxItemDraw(y, item) + local dy = (self.itemheight - FONT_HGT_MEDIUM) / 2 + self:drawText(item.text, 16, y + dy, 1, 1, 1, 1, UIFont.Medium) + self:drawRectBorder(0, y, self:getWidth(), self.itemheight, 0.5, self.borderColor.r, self.borderColor.g, self.borderColor.b) + + for _, data in pairs(item.item) do + local isViewed = ModNewsAPI.GetArticleIsViewed(data.modID, data.articleName) + if isViewed == false then + self:drawText("[!!!]", self.width - 50, y + dy, 0, 1, 0, 1, UIFont.Medium) + end + end + return y + self.itemheight +end + +function ModNewsPanel:modArticleItemDraw(y, item) + local dy = (self.itemheight - FONT_HGT_MEDIUM) / 2 + self:drawText(item.text, 16, y + dy, 1, 1, 1, 1, UIFont.Medium) + self:drawRectBorder(0, y, self:getWidth(), self.itemheight, 0.5, self.borderColor.r, self.borderColor.g, self.borderColor.b) + + local isViewed = ModNewsAPI.GetArticleIsViewed(item.item.modID, item.item.articleName) + if isViewed == false then + self:drawText("[!!!]", self.width - 50, y + dy, 0, 1, 0, 1, UIFont.Medium) + end + + return y + self.itemheight +end + +function ModNewsPanel:onOptionMouseDown(button, x, y) + if button.internal == "BACK" then + self:setVisible(false) + self:removeFromUIManager() + + local Data = ModNewsAPI.GetAll() + local fileWriter = getFileWriter("CAPI_modNewsData.txt", true, false) + fileWriter:write(JsonAPI.Encode(Data)) + fileWriter:close() + end +end + +function ModNewsPanel:instantiate() + self.javaObject = UIElement.new(self) + self.javaObject:setX(self.x) + self.javaObject:setY(self.y) + self.javaObject:setHeight(self.height) + self.javaObject:setWidth(self.width) + self.javaObject:setAnchorLeft(self.anchorLeft) + self.javaObject:setAnchorRight(self.anchorRight) + self.javaObject:setAnchorTop(self.anchorTop) + self.javaObject:setAnchorBottom(self.anchorBottom) + self:createChildren() +end + +function ModNewsPanel:new(x, y, width, height) + local o = {} + o = ISPanelJoypad:new(x, y, width, height) + setmetatable(o, self) + self.__index = self + + o.backgroundColor = {r=0, g=0, b=0, a=0.0} + o.borderColor = {r=1, g=1, b=1, a=0.0} + o.itemheightoverride = {} + o.anchorLeft = true + o.anchorRight = false + o.anchorTop = true + o.anchorBottom = false + o.colorPanel = {} + + return o +end + +return ModNewsPanel diff --git a/Contents/mods/CommunityAPI/media/lua/client/ModNewsAPI/README.md b/Contents/mods/CommunityAPI/media/lua/client/ModNewsAPI/README.md new file mode 100644 index 0000000..efe4712 --- /dev/null +++ b/Contents/mods/CommunityAPI/media/lua/client/ModNewsAPI/README.md @@ -0,0 +1,39 @@ +# ModNewsAPI +**Developer:** Aiteron +**Contributors:** - +**Package:** CommunityAPI.Client.ModNews + +## Description +Add news article for your mod updates. + +## Methods + +### AddArticle(modID, articleName, articleTextName, lastUpdateDate) +Add a new Article for your mod + +| Param | Type | Description | +|-----------------|--------|---------------------------------------------------------------------------------------------------------------------| +| modID | string | The mod ID | +| articleName | string | The article Name | +| articleTextName | string | Article text name from Translate | +| lastUpdateDate | string | String with date of last update. If you changed article and want to notify that article updated - change this param | + +## Examples +```lua +require("CommunityAPI") +local ModNewsAPI = CommunityAPI.Client.ModNews + +--- Add an article for your mod +ModNewsAPI.AddArticle( + "MyModId", + "The article name in the list", + "The article text here\nwith line breaks if desired", + "November 1st, 2021"); + +--- Add a translatable article for your mod +ModNewsAPI.AddArticle( + "MyModId", + getText("Translate_Article_Name"), + getText("Translate_Article_Text"), + "November 1st, 2021"); +``` \ No newline at end of file diff --git a/Contents/mods/CommunityAPI/media/lua/shared/CommunityAPI/StringUtils.lua b/Contents/mods/CommunityAPI/media/lua/shared/CommunityAPI/StringUtils.lua index ae896f7..0948efc 100644 --- a/Contents/mods/CommunityAPI/media/lua/shared/CommunityAPI/StringUtils.lua +++ b/Contents/mods/CommunityAPI/media/lua/shared/CommunityAPI/StringUtils.lua @@ -37,4 +37,25 @@ function StringUtils.NumberToDecimalString(value, _decimal) return string.format("%.".._decimal.."f", value); end +---Parse each line of site html file by parseLineFunc +---@param url string Url ("https://" or "http://") +---@param parseLineFunc function Get line and return useful data item (not empty string or any object) else nil or empty string +---@return table any List with all useful data items +function StringUtils.ParseSite(url, parseLineFunc) + local siteData = getUrlInputStream(url) + local resultData = {} + + if siteData ~= nil then + local currentLine = siteData:readLine() + while currentLine ~= nil do + local dataItem = parseLineFunc(currentLine) + if dataItem ~= nil and dataItem ~= "" then + table.insert(resultData, dataItem) + end + currentLine = siteData:readLine() + end + end + return resultData +end + return StringUtils \ No newline at end of file diff --git a/Contents/mods/CommunityAPI/media/lua/shared/Translate/EN/UI_EN.txt b/Contents/mods/CommunityAPI/media/lua/shared/Translate/EN/UI_EN.txt index bfdc81d..44eabfd 100644 --- a/Contents/mods/CommunityAPI/media/lua/shared/Translate/EN/UI_EN.txt +++ b/Contents/mods/CommunityAPI/media/lua/shared/Translate/EN/UI_EN.txt @@ -8,5 +8,8 @@ UI_EN = { UI_EMS_CopyLink = "Copy link" UI_EMS_CopyLocation = "Copy location", UI_EMS_CopyID = "Copy ID", - UI_EMS_CopyWorkshopID = "Copy Workshop ID" + UI_EMS_CopyWorkshopID = "Copy Workshop ID", + + UI_modNews_button = "Mod Info", + UI_modNews_articleLabel = "Articles", } diff --git a/Contents/mods/CommunityAPI/media/lua/shared/Translate/RU/UI_RU.txt b/Contents/mods/CommunityAPI/media/lua/shared/Translate/RU/UI_RU.txt index fc4c152..a312337 100644 --- a/Contents/mods/CommunityAPI/media/lua/shared/Translate/RU/UI_RU.txt +++ b/Contents/mods/CommunityAPI/media/lua/shared/Translate/RU/UI_RU.txt @@ -8,5 +8,8 @@ UI_RU = { UI_EMS_CopyLink = "Копировать ссылку" UI_EMS_CopyLocation = "Копировать расположение", UI_EMS_CopyID = "Копировать ID", - UI_EMS_CopyWorkshopID = "Копировать Workshop ID" + UI_EMS_CopyWorkshopID = "Копировать Workshop ID", + + UI_modNews_button = "Мод Инфо", + UI_modNews_articleLabel = "Статьи" } diff --git a/Contents/mods/CommunityAPI/media/ui/ModNews/notifyIcon.png b/Contents/mods/CommunityAPI/media/ui/ModNews/notifyIcon.png new file mode 100644 index 0000000..57bc9cd Binary files /dev/null and b/Contents/mods/CommunityAPI/media/ui/ModNews/notifyIcon.png differ