Mercurial > wow > squawk
diff Squawk.lua @ 18:a3328fffef5c
Split of main file into components
author | wobin |
---|---|
date | Thu, 07 May 2009 02:52:23 +1000 |
parents | 2a73deb7bc54 |
children | 431f2fce08f2 |
line wrap: on
line diff
--- a/Squawk.lua Sun May 03 00:00:24 2009 +1000 +++ b/Squawk.lua Thu May 07 02:52:23 2009 +1000 @@ -1,566 +1,47 @@ --- A Twitter client of sorts for World of Warcraft --- Author: Wobin --- Email: wobster@gmail.com --- -Squawk = LibStub("AceAddon-3.0"):NewAddon("Squawk") - -Squawk.Model = {} -Squawk.View = {} -Squawk.Controller = {} - -local Model = Squawk.Model -local View = Squawk.View -local Controller = Squawk.Controller - -Model.UserSettings = {} -local Settings = Model.UserSettings - -local defaults = { - profile = { - Squawks = {}, - Follower = {}, - Following = {}, - Pending = {}, - Requested = {}, - Blocked = {}, - } -} - -function Squawk:OnInitialize() - Model.db = LibStub("AceDB-3.0"):New("SquawkDB", defaults) - Model.Squawks = Model.db.profile.Squawks - Settings.Follower = Model.db.profile.Follower - Settings.Following = Model.db.profile.Following - Settings.Pending = Model.db.profile.Pending - Settings.Requested = Model.db.profile.Requested - Settings.Blocked = Model.db.profile.Blocked - Settings.Private = Model.db.profile.Private - - LibStub("AceComm-3.0"):Embed(Controller) - LibStub("AceTimer-3.0"):Embed(Controller) - Controller:RegisterComm("Squawk", Controller.ReceiveMessage) - LibStub("AceConsole-3.0"):Embed(View) - -end - --- Model -- ---[[ ---Each Squawk will have the following information: --- * Owner (Name) --- * Time (Epoch) --- * Message (140 characters) --- * ReplyTo (Name) --- * Related (Names) --- --- Each User will have the following lists: --- * Follower --- * Following --- * Blocked --- * Pending (Requests to follow that you haven't acted on) --- * Requested (Requests to follow that you have made) --- * Privacy State --- --- A user can only request to follow an online person. Requests can be approved --- on or offline, but the initial request must be made online. --- --- When a user makes a request to follow a private user, the subsequent paths occur: --- - Followee is added to Settings.Requested --- - Followee receives 'follow request' -> (their) Settings.Pending --- - Followee acts on request -> (their) Settings.Pending cleared --- 1) Follwer is online --- - Follower receives 'request accepted' -> Added to Settings.Following and --- cleared from Settings.Requested --- 2) Follower is offline --- - The next time Follower is online and recieves a Squawk we check if there --- is a Settings.Requested for that name, and if so assume they have approved --- and clear/add records appropriately. --- --- For updating, there can be a few methods. --- --- Guild open: you're not private, you broadcast to the guild your last X --- squawks on login --- --- followers: ---]] -Model.Squawks = {} -local Squawks = Model.Squawks -Squawks.Main = {} -Squawks.Owners = {} - -local function wrap(str, limit) - limit = limit or 72 - local here = 1 - return str:gsub("(%s+)()(%S+)()", - function(sp, st, word, fi) - if fi-here > limit then - here = st - return "\n"..word - end - end) -end - -function Squawks:new(Message, Owner) - local o = {} - o.Owner = Owner or UnitName("player") - o.Message = wrap(Message) - o.Time = time() - local reply, to = strsplit("@", ((strsplit(" ", Message)))) - if reply == "" then - o.ReplyTo = to - end - - o.Related = {} - - for word in string.gmatch(Message, "@(%a+)") do - if word ~= o.ReplyTo or "" then - table.insert(o.Related, word) - end - end - - table.insert(self.Main, o) - - if not self.Owners[Owner] then - self.Owners[Owner] = {} - end - table.insert(self.Owners[Owner], o) - - return o -end - -function Squawks:Sort(Squawks) - table.sort(Squawks or self.Main, function(a,b) return a.Time > b.Time end) - return Squawks or self.Main -end - -function Squawks:GetOwn(Squawks) - local mine = {} - for _, squawk in ipairs(Squawks or self.Main) do - if squawk.Owner == UnitName("player") then - table.insert(mine, squawk) - end - end - return self:Sort(mine) -end - -function Squawks:GetLast10(Squawks) - local mine = {} - Squawks = Squawks or self.Main - local limit = #Squawks < 10 and #Squawks or 10 - - Squawks = Squawk:Sort(Squawks) - - for i=1,limit do - table.insert(mine, Squawks[i]) - end - return mine -end - --- initially called with no arguments to get the latest timestamp of --- my squawks, or with a name to find the latest timestamp of all --- squawks from that user -function Squawks:GetLatestTimestamp(Name, Squawks) - if Name then - if self.Owners[Name] then - return self:GetLatestTimestamp(nil, self.Owners[Name]) - else - return -1 -- No squawks exist for that name in our records - end - end - - Squawks = Squawks or self.Main or {} - local latest = self:Sort(Squawks) - return latest and #latest > 0 and latest[1].Time or -1 -end - -function Squawks:GetLatestSquawks(Timestamp) - local latest = {} - for i, squawk in ipairs(self:Sort()) do - if squawk.Time > Timestamp and i < 10 then - table.insert(latest, squawk) - else - return latest - end - end -end - -function Settings:IsPrivate() - return Settings.Private -end - -function Settings:TogglePrivate() - Settings.Private = not Settings.Private -end - -function Settings:AddFollower(Name) - Settings.Follower[Name] = 1 - self:RemovePending(Name) -end - -function Settings:AddFollowing(Name) - Settings.Following[Name] = 1 - self:RemoveRequested(Name) -end - -function Settings:AddBlock(Name) - Settings.Blocked[Name] = 1 - self:RemoveFollower(Name) - self:RemoveFollowing(Name) -end - -function Settings:AddPending(Name) - Settings.Pending[Name] = 1 -end - -function Settings:AddRequested(Name) - Settings.Requested[Name] = 1 -end - -function Settings:RemoveFollower(Name) - if Settings.Follower[Name] then - Settings.Follower[Name] = nil - end -end - -function Settings:RemoveFollowing(Name) - if Settings.Following[Name] then - Settings.Following[Name] = nil - end -end - -function Settings:RemoveBlock(Name) - if Settings.Blocked[Name] then - Settings.Blocked[Name] = nil - end -end - -function Settings:RemovePending(Name) - if Settings.Pending[Name] then - Settings.Pending[Name] = nil - end -end - -function Settings:RemoveRequested(Name) - if Settings.Requested[Name] then - Settings.Requested[Name] = nil - end -end - ---Controller-- - -function Controller:TheyWantToFollowMe(Name) - if Settings:IsPrivate() then - Settings:AddPending(Name) - self:PutForwardFollowRequest(Name) - self:SendMessageToTarget(Name, "#Pending|"..UnitName("player")) - else - Settings:AddFollower(Name) - View:NotifyOfNewFollower(Name) - self:SendMessageToTarget(Name, "#Follow|"..UnitName("player")) - end -end - -function Controller:TheyWantToUnfollowMe(Name) - Settings:RemoveFollower(Name) -end - -function Controller:IWantToFollowThem(Name) - self:SendMessageToTarget(Name, "#Request|"..UnitName("player")) - Settings:AddRequested(Name) -end - -function Controller:IWantToUnfollowThem(Name) - Settings:RemoveFollowing(Name) - self:SendMessageToTarget(Name, "#Unfollow|"..UnitName("player")) - View:NotifyOfUnfollowing(Name) -end - -function Controller:IAmNowFollowingThem(Name) - Settings:AddFollowing(Name) - View:NotifyOfNewFollowing(Name) -end - -function Controller:AddANewSquawk(Name, Message, Source) - if not Settings.Blocked[Name] then - - if Source == "WHISPER" then - if Settings.Requested[Name] then -- We've been approved offline! - Settings:AddFollowing(Name) - end - - if not Settings.Following[Name] then -- If we're no longer following this person - self:SendMessageToTarget(Name, "#Unfollow|"..UnitName("player")) - return - end - end - - if Source == "GUILD" and Name == UnitName("player") then - return - end - - table.insert(Model.Squawks, Squawk:new(Message, Name)) - View:UpdateSquawkList() - end -end - -local trigger -local function RepressFailure(frame, event, ...) - if arg1:match(string.gsub(ERR_CHAT_PLAYER_NOT_FOUND_S, "%%s", "(.*)")) then - if trigger then Controller:CancelTimer(trigger, true) end - trigger = Controller:ScheduleTimer( - function() - ChatFrame_RemoveMessageEventFilter("CHAT_MSG_SYSTEM", RepressFailure) - end, 3) -- Give it three seconds and then remove the filter. - return true - else - return false, unpack(...) - end -end - -function Controller:SendNewSquawk(Message) - if not Settings:IsPrivate() then - self:SendMessageToGuild("#Squawk|"..UnitName("player").."|"..Message) - end - - self:AddANewSquawk(UnitName("player"), Message) - for name, _ in pairs(Settings.Following) do - self:SendMessageToTarget(name, "#Squawk|"..UnitName("player").."|"..Message) - end -end - -function Controller:ImPending(Name) - View:NotifyOfPending(Name) -end - -function Controller:PutForwardFollowRequest(Name) - View:NotifyOfPendingRequest(Name) -end - -function Controller:ApprovePendingRequest(Name) - Settings:AddFollower(Name) - View:NotifyOfNewFollower(Name) - self:SendMessageToTarget(Name, "#Follow|"..UnitName("player")) -end - - - -function Controller:SendMessageToTarget(Name, Message) - ChatFrame_AddMessageEventFilter("CHAT_MSG_SYSTEM", RepressFailure) - self:SendCommMessage("Squawk", Message, "WHISPER", Name) -end - -function Controller:SendMessageToGuild(Message) - self:SendCommMessage("Squawk", Message, "GUILD") -end - -local Parse = { - ["#Pending"] = Controller.ImPending, - ["#Follow"] = Controller.IAmNowFollowingThem, - ["#Unfollow"] = Controller.TheyWantToUnfollowMe, - ["#Squawk"] = Controller.AddANewSquawk, - ["#Request"] = Controller.TheyWantToFollowMe, - } - -function Controller:ReceiveMessage(Message, Distribution, Sender) - local command, name, info = strsplit("|",Message) - View:Print(Distribution..":"..Message) - Parse[command](Controller, name, info, Distribution) -end - --- View -- - -function View:UpdateSquawkList() - self:Print("Updated Squawk List") - self:ShowMeMySquawks() -end - -function View:NotifyOfPending(Name) - self:Print(Name.." will have to approve your request") -end - -function View:NotifyOfPendingRequest(Name) - self:Print(Name.." wants to follow you.") -end - -function View:NotifyOfNewFollowing(Name) - self:Print("You are now following "..Name) -end - -function View:NotifyOfUnfollowing(Name) - self:Print("You are no longer following "..Name) -end - -function View:NotifyOfNewFollower(Name) - self:Print(Name.." is now following you") -end - -function View:ShowMeMySquawks() - for _,squawk in ipairs(Model.Squawks.Main) do - self:Print(squawk.Message) - end -end - -function View:ShowMeMyFollowers() - self:Print("My followers are:") - for name,_ in pairs(Settings.Follower) do - self:Print(name) - end -end - -function View:ShowMeWhoImFollowing() - self:Print("I am following:") - for name,_ in pairs(Settings.Following) do - self:Print(name) - end -end - -function View:ShowMeWhoIveBlocked() - self:Print("I've blocked:") - for name,_ in pairs(Settings.Blocked) do - self:Print(name) - end -end - -local TimeSpan = { [1] = {"second", 60, 1}, - [2] = {"minute", 3600, 60}, - [3] = {"hour", 86400, 3600} } - -function View:GetTime(stime) - local lapsed = difftime(time(), stime) - if lapsed < 86400 then -- if we're still in the same day... - for _,span in ipairs(TimeSpan) do - if lapsed < span[2] then - local timespan = math.floor(lapsed/span[3]) - if timespan == 1 then - timespan = timespan .." ".. span[1] - else - timespan = timespan .. " ".. span[1].."s" - end - return timespan.. " ago" - end - end - end - return date("%I:%M %p %b %d", stime) -end - -local LDBFeed = LibStub("LibDataBroker-1.1"):NewDataObject("Squawk", {type = "data source", text = "Awk!"}) -local QTip = LibStub("LibQTip-1.0") -local QTipClick = LibStub("LibQTipClick-1.0") -local tooltip = {} - -local function HideTooltip() - if MouseIsOver(tooltip) then return end - tooltip:SetScript("OnLeave", nil) - tooltip:Hide() - QTip:Release(tooltip) - tooltip = nil -end - -local function ReplyToMe(cell, Owner, event) - View:Print("Replying to @"..Owner) -end - -local function AddLine(tooltip, Line, Number, Owner, TimeStamp) - local x,y - if #Line < 79 then - y,x = tooltip:AddNormalLine(Number, Owner, Line, TimeStamp) - else - y,x = tooltip:AddNormalLine(Number, Owner, Line:sub(1, 80).."-", TimeStamp) - AddLine(tooltip, Line:sub(81)) - end - if not TimeStamp then return end - - -- Now add the reply clickback - tooltip:SetCell(y, 5, " ", Owner) - tooltip.lines[y].cells[5]:SetBackdrop({bgFile= "Interface\\Addons\\Squawk\\reply"}) - if not tooltip.lines[y].cells[5]:GetScript("OnHide") then - tooltip.lines[y].cells[5]:SetScript("OnHide", function(self) self:SetBackdrop(nil) self:SetScript("OnHide", nil) end) - end - -- Reply clickback finished -end - -function LDBFeed:OnEnter() - tooltip = QTipClick:Acquire("Squawk",5, "LEFT", "CENTER", "LEFT", "RIGHT", "RIGHT") - tooltip:Clear() - tooltip:SetCallback("OnMouseDown", ReplyToMe) - self.tooltip = tooltip - for i,squawk in ipairs(Squawk:GetLast10(Model.Squawks)) do - local head = true - local message = {strsplit("\n",squawk.Message)} - for _,line in ipairs(message) do - if head then - AddLine(tooltip, line, i..".", squawk.Owner, View:GetTime(squawk.Time)) - head = false - else - AddLine(tooltip, line) - end - end - end - tooltip:SmartAnchorTo(self) - tooltip:SetScript("OnLeave", HideTooltip) - tooltip:Show() -end - -function LDBFeed:OnLeave() - HideTooltip() -end ---[[ - -function LDBFeed:OnClick(button) - editbox:ClearAllPoints() - editbox:SetPoint(GetTipAnchor(self)) - editbox:Show() -end - -local function GetTipAnchor(frame) - if not x or not y then return "TOPLEFT", frame, "BOTTOMLEFT" end - local hhalf = (x > UIParent:GetWidth()*2/3) and "RIGHT" or (x < UIParent:GetWidth()/3) and "LEFT" or "" - local vhalf = (y > UIParent:GetHeight()/2) and "TOP" or "BOTTOM" - return vhalf..hhalf, frame, (vhalf == "TOP" and "BOTTOM" or "TOP")..hhalf -end - -local editbox = CreateFrame('EditBox', nil, UIParent) -editbox:Hide() -editbox:SetAutoFocus(true) -editbox:SetHeight(32) -editbox:SetWidth(350) -editbox:SetFrameStrata("HIGH") -editbox:SetFontObject('GameFontHighlightSmall') -lib.editbox = editbox - -editbox:SetScript("OnEscapePressed", editbox.ClearFocus) -editbox:SetScript("OnEnterPressed", editbox.ClearFocus) -editbox:SetScript("OnEditFocusLost", editbox.Hide) -editbox:SetScript("OnEditFocusGained", editbox.HighlightText) -editbox:SetScript("OnTextChanged", function(self) - self:SetText(self:GetParent().val) - self:HighlightText() -end) - - local left = editbox:CreateTexture(nil, "BACKGROUND") - left:SetWidth(8) left:SetHeight(20) - left:SetPoint("LEFT", -5, 0) - left:SetTexture("Interface\\Common\\Common-Input-Border") - left:SetTexCoord(0, 0.0625, 0, 0.625) - - local right = editbox:CreateTexture(nil, "BACKGROUND") - right:SetWidth(8) right:SetHeight(20) - right:SetPoint("RIGHT", 0, 0) - right:SetTexture("Interface\\Common\\Common-Input-Border") - right:SetTexCoord(0.9375, 1, 0, 0.625) - - local center = editbox:CreateTexture(nil, "BACKGROUND") - center:SetHeight(20) - center:SetPoint("RIGHT", right, "LEFT", 0, 0) - center:SetPoint("LEFT", left, "RIGHT", 0, 0) - center:SetTexture("Interface\\Common\\Common-Input-Border") - center:SetTexCoord(0.0625, 0.9375, 0, 0.625) - -function lib.OpenEditbox(self) - editbox:SetText(self.val) - editbox:SetParent(self) - editbox:SetPoint("LEFT", self) - editbox:SetPoint("RIGHT", self) - editbox:Show() -end ---]] - +-- A Twitter client of sorts for World of Warcraft +-- Author: Wobin +-- Email: wobster@gmail.com +-- +Squawk = LibStub("AceAddon-3.0"):NewAddon("Squawk") + +Squawk.Model = {} +Squawk.View = {} +Squawk.Controller = {} + +local Model = Squawk.Model +local View = Squawk.View +local Controller = Squawk.Controller + +Model.UserSettings = {} +local Settings = Model.UserSettings + +local defaults = { + profile = { + Squawks = {}, + Follower = {}, + Following = {}, + Pending = {}, + Requested = {}, + Blocked = {}, + } +} +local SquawkViewMeta = { __tostring = function() return "SquawkView" end } + +function Squawk:OnInitialize() + Model.db = LibStub("AceDB-3.0"):New("SquawkDB", defaults) + Model.Squawks.Main = Model.db.profile.Squawks + Settings.Follower = Model.db.profile.Follower + Settings.Following = Model.db.profile.Following + Settings.Pending = Model.db.profile.Pending + Settings.Requested = Model.db.profile.Requested + Settings.Blocked = Model.db.profile.Blocked + Settings.Private = Model.db.profile.Private + + LibStub("AceComm-3.0"):Embed(Controller) + LibStub("AceTimer-3.0"):Embed(Controller) + Controller:RegisterComm("Squawk", Controller.ReceiveMessage) + LibStub("AceConsole-3.0"):Embed(View) + setmetatable(View, SquawkViewMeta) + + Model.Squawks.Reload(Model.Squawks) -- Retrain the table lookups +end