Mercurial > wow > squawk
view Squawk.lua @ 16:6c28e55a00cf
hmm
author | wobin |
---|---|
date | Sat, 02 May 2009 23:54:32 +1000 |
parents | 9e61a930b822 |
children | 2a73deb7bc54 |
line wrap: on
line source
-- 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 --]]