Post Metrics
This commit is contained in:
parent
8a691b5e07
commit
8a86a1eb38
|
@ -0,0 +1,144 @@
|
|||
// Made by Lumaa
|
||||
|
||||
import Foundation
|
||||
import Charts
|
||||
|
||||
/// This gets metrics on the selected account from the ``Client``
|
||||
final class MetricsManager {
|
||||
private var client: Client
|
||||
|
||||
private var measured: Bool = false
|
||||
|
||||
private(set) public var postCount: [IntData] = []
|
||||
private(set) public var postType: [StatusTypeData] = []
|
||||
|
||||
init(accountManager: AccountManager) {
|
||||
if let cli = accountManager.getClient() {
|
||||
self.client = cli
|
||||
}
|
||||
fatalError("Account Manager doesn't have a Client bound")
|
||||
}
|
||||
|
||||
init(client: Client) {
|
||||
self.client = client
|
||||
}
|
||||
|
||||
/// Only gets the last few posts count AND ``StatusTypeData``
|
||||
private func getLastPosts() async -> ([IntData], [StatusTypeData]) {
|
||||
guard let accountDetail: Account = try? await self.client.get(endpoint: Accounts.verifyCredentials), let statusesCount: Int = accountDetail.statusesCount else {
|
||||
fatalError("Couldn't verify creds for Metrics")
|
||||
}
|
||||
|
||||
if let posts: [Status] = try? await self.client.get(
|
||||
endpoint: Accounts.statuses(id: accountDetail.id, sinceId: nil, tag: nil, onlyMedia: nil, excludeReplies: nil, pinned: nil)
|
||||
) {
|
||||
var countData: [IntData] = []
|
||||
var typeData: [StatusTypeData] = []
|
||||
|
||||
posts.reversed().forEach { post in // go through posts backwards
|
||||
let i: Int = posts.firstIndex(of: post) ?? -1 // latest post is first, oldest is last
|
||||
|
||||
let newCountData: IntData = .init(date: post.createdAt.asDate, count: statusesCount - i, fullCount: statusesCount)
|
||||
let newTypeData: StatusTypeData = .init(date: post.createdAt.asDate, type: post.getType())
|
||||
|
||||
countData.append(newCountData)
|
||||
typeData.append(newTypeData)
|
||||
}
|
||||
|
||||
return (countData, typeData)
|
||||
} else {
|
||||
fatalError("Couldn't fetch account's statuses")
|
||||
}
|
||||
}
|
||||
|
||||
/// Data used for integer Metrics
|
||||
struct IntData: GraphData {
|
||||
let date: Date
|
||||
let count: Int
|
||||
let fullCount: Int
|
||||
|
||||
var difference: Int {
|
||||
fullCount - count
|
||||
}
|
||||
|
||||
var plottableCount: PlottableValue<Int> {
|
||||
.value(String(localized: "metrics.status.count"), count)
|
||||
}
|
||||
|
||||
init(date: Date, count: Int, fullCount: Int) {
|
||||
self.date = date
|
||||
self.count = count
|
||||
self.fullCount = fullCount
|
||||
}
|
||||
}
|
||||
|
||||
struct StatusTypeData: GraphData {
|
||||
let date: Date
|
||||
let type: Status.StatusType
|
||||
|
||||
var label: String {
|
||||
self.type.localized
|
||||
}
|
||||
|
||||
var plottableType: PlottableValue<String> {
|
||||
.value(String(localized: "metrics.status.count"), label)
|
||||
}
|
||||
|
||||
init(date: Date, type: Status.StatusType) {
|
||||
self.date = date
|
||||
self.type = type
|
||||
}
|
||||
}
|
||||
|
||||
protocol GraphData {
|
||||
var date: Date { get }
|
||||
}
|
||||
}
|
||||
|
||||
extension MetricsManager.GraphData {
|
||||
var plottableDate: PlottableValue<Date> {
|
||||
.value(String(localized: "metrics.any.date"), date)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Status Type
|
||||
extension Status {
|
||||
func getType() -> Status.StatusType {
|
||||
let isReply: Bool = self.inReplyToId != nil
|
||||
let isDirect: Bool = self.visibility == .direct
|
||||
|
||||
if !isReply && !isDirect {
|
||||
return Self.StatusType.post
|
||||
} else if isReply && !isDirect {
|
||||
return Self.StatusType.reply
|
||||
} else if !isReply && isDirect {
|
||||
return Self.StatusType.direct
|
||||
} else if isReply && isDirect {
|
||||
return Self.StatusType.directReply
|
||||
}
|
||||
return Self.StatusType.post
|
||||
}
|
||||
|
||||
enum StatusType {
|
||||
case post
|
||||
case reply
|
||||
case direct
|
||||
case directReply
|
||||
case unknown
|
||||
|
||||
var localized: String {
|
||||
switch self {
|
||||
case .post:
|
||||
String(localized: "status.type.post")
|
||||
case .reply:
|
||||
String(localized: "status.type.reply")
|
||||
case .direct:
|
||||
String(localized: "status.type.direct")
|
||||
case .directReply:
|
||||
String(localized: "status.type.direct-reply")
|
||||
default:
|
||||
String(localized: "status.type.unknown")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2072,6 +2072,38 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"metrics.any.date" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Date"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Date"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"metrics.status.count" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Post Count"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Nombre de publications"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"posting.alt.apply" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
|
@ -4370,6 +4402,86 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"status.type.direct" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Direct Message"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Message privé"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"status.type.direct-reply" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Reply to a Message"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Réponse à un message"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"status.type.post" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Post"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Publication"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"status.type.reply" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Reply"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Réponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"status.type.unknown" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Undetermined"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Indéterminé"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"support" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
|
|
Loading…
Reference in New Issue