Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 103 additions & 11 deletions Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
private var username = UserDefaults.standard.string(forKey: Consts.usernameDefaultKey) ?? ""
private var friendUsername = UserDefaults.standard.string(forKey: Consts.friendUsernameDefaultKey) ?? ""
private var goal = UserDefaults.standard.integer(forKey: Consts.goalDefaultKey)
private var selfCompareOffset = UserDefaults.standard.integer(forKey: Consts.selfCompareOffsetDefaultKey)
private let menu = NSMenu().then {
$0.title = ""
}
Expand Down Expand Up @@ -73,6 +74,20 @@ class AppDelegate: NSObject, NSApplicationDelegate {
$0.tag = 6
$0.keyEquivalent = "d"
}

private let pastSelfMenuItem = NSMenuItem().then {
$0.title = Localized.setPastSelf
$0.action = #selector(onChangePastSelfClick)
$0.tag = 11
$0.keyEquivalent = "p"
}

private let removePastSelfMenuItem = NSMenuItem().then {
$0.title = Localized.removePastSelf
$0.action = #selector(onRemovePastSelfClick)
$0.tag = 11
$0.keyEquivalent = ""
}

private let settingMenuItem = NSMenuItem().then {
$0.title = Localized.setting
Expand Down Expand Up @@ -125,6 +140,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
menu.addItem(.separator())
menu.addItem(friendMenuItem)
menu.addItem(RemoveFriendMenuItem)
menu.addItem(pastSelfMenuItem)
menu.addItem(removePastSelfMenuItem)
menu.addItem(.separator())
menu.addItem(goalMenuItem)
menu.addItem(.separator())
Expand All @@ -140,19 +157,29 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}

private func updateUI() {

var withFriend = ""
if !friendUsername.isEmpty {
withFriend = Localized.withFriend.replacingOccurrences(of: "${username}", with: friendUsername)
} else if selfCompareOffset > 0 {
withFriend = Localized.withPastSelf.replacingOccurrences(of: "${day}", with: String(selfCompareOffset))
}

let userMenuItemTitle = Localized.hello.replacingOccurrences(of: "${username}", with: username).replacingOccurrences(of: "${withFriend}", with: withFriend)
userMenuItem.attributedTitle = NSAttributedString(string: userMenuItemTitle)

let friendMenuItemTitle = self.friendUsername.isEmpty ? Localized.setFriendUsername : Localized.changeFriendUsername
friendMenuItem.title = friendMenuItemTitle

RemoveFriendMenuItem.isHidden = self.friendUsername.isEmpty

let pastSelfActive = self.selfCompareOffset > 0
let friendActive = !self.friendUsername.isEmpty

friendMenuItem.isHidden = pastSelfActive
RemoveFriendMenuItem.isHidden = !friendActive || pastSelfActive

pastSelfMenuItem.title = pastSelfActive ? Localized.changePastSelf : Localized.setPastSelf
pastSelfMenuItem.isHidden = friendActive
removePastSelfMenuItem.isHidden = !pastSelfActive || friendActive
}

private func showSettingAlert() {
Expand Down Expand Up @@ -224,6 +251,37 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}
}

private func showChangePastSelfAlert() {
let alert = NSAlert()
let offsetTextField = NSTextField(frame: NSRect(x: 0, y: 0, width: 300, height: 20))
let formatter = IntegerValueFormatter()
offsetTextField.formatter = formatter
offsetTextField.placeholderString = self.selfCompareOffset > 0 ? String(self.selfCompareOffset) : "1"

alert.messageText = Localized.setPastSelf
alert.informativeText = Localized.pastSelfInformation
alert.alertStyle = .informational
alert.accessoryView = offsetTextField
alert.addButton(withTitle: Localized.ok)
alert.addButton(withTitle: Localized.cancel)
alert.window.initialFirstResponder = alert.accessoryView

if alert.runModal() == .alertFirstButtonReturn {
let raw = offsetTextField.stringValue.trimmingCharacters(in: .whitespacesAndNewlines)
let offset: Int
if raw.isEmpty {
offset = self.selfCompareOffset > 0 ? self.selfCompareOffset : 1
} else {
offset = offsetTextField.integerValue
}
if offset <= 0 {
removeSelfCompareInfo()
} else {
changeSelfCompareOffset(with: offset)
}
}
}

private func showChangeGoalAlert() {
let alert = NSAlert()
let goalTextField = NSTextField(frame: NSRect(x: 0, y: 0, width: 300, height: 20))
Expand Down Expand Up @@ -303,6 +361,14 @@ class AppDelegate: NSObject, NSApplicationDelegate {
showChangeGoalAlert()
}

@objc func onChangePastSelfClick(){
Comment thread
kidager marked this conversation as resolved.
Outdated
showChangePastSelfAlert()
}

@objc func onRemovePastSelfClick(){
Comment thread
kidager marked this conversation as resolved.
Outdated
removeSelfCompareInfo()
}

private func changeUsername(withUsername username: String) {
UserDefaults.standard.setValue(username, forKey: Consts.usernameDefaultKey)
self.username = UserDefaults.standard.string(forKey: Consts.usernameDefaultKey)!
Expand All @@ -313,15 +379,37 @@ class AppDelegate: NSObject, NSApplicationDelegate {
private func changeFriendUsername(withUsername username: String) {
UserDefaults.standard.setValue(username, forKey: Consts.friendUsernameDefaultKey)
self.friendUsername = UserDefaults.standard.string(forKey: Consts.friendUsernameDefaultKey)!


UserDefaults.standard.setValue(0, forKey: Consts.selfCompareOffsetDefaultKey)
self.selfCompareOffset = 0

refresh()
}

private func removeFriendinfo(){
UserDefaults.standard.setValue("", forKey: Consts.friendUsernameDefaultKey)
self.friendUsername = ""
self.friendContributes = []


refresh()
}

private func changeSelfCompareOffset(with offset: Int) {
UserDefaults.standard.setValue(offset, forKey: Consts.selfCompareOffsetDefaultKey)
self.selfCompareOffset = UserDefaults.standard.integer(forKey: Consts.selfCompareOffsetDefaultKey)

UserDefaults.standard.setValue("", forKey: Consts.friendUsernameDefaultKey)
self.friendUsername = ""
self.friendContributes = []

refresh()
}

private func removeSelfCompareInfo() {
UserDefaults.standard.setValue(0, forKey: Consts.selfCompareOffsetDefaultKey)
self.selfCompareOffset = 0
self.friendContributes = []

refresh()
}

Expand Down Expand Up @@ -484,6 +572,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
} else{
self.myContributes = contributeDataList
self.mystreaks = self.parseHtmltoDataForCount(html: html)
if self.friendUsername.isEmpty && self.selfCompareOffset > 0 {
self.friendContributes = self.parseHtmltoData(html: html, daysBack: self.selfCompareOffset)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This call triggers a redundant full parse of the HTML string using SwiftSoup. Note that the HTML is already parsed at line 569 (for contributeDataList) and again at line 574 (for mystreaks). Adding a third parse here significantly impacts performance, especially on slower connections or larger contribution graphs.

Consider refactoring parseHtmltoData to accept a pre-parsed Document or to return the full list of contribution data so that the caller can slice it as needed without re-parsing the entire document.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. Addressed in 2a9f338 by extracting parseSortedDays(html:), which performs the SwiftSoup parse, sort, and tooltip injection once. parseHtmltoData and parseHtmltoDataForCount now take the pre-parsed [Element] and only slice/walk it. The HTML is parsed exactly once per fetch, regardless of whether self-compare is on. As a side effect, this also fixes the pre-existing 2-parse pattern (one for myContributes, one for mystreaks).

}
}

if group != nil {
Expand Down Expand Up @@ -531,17 +622,18 @@ class AppDelegate: NSObject, NSApplicationDelegate {
return integerValue
}

private func parseHtmltoData(html: String) -> [ContributeData] {
private func parseHtmltoData(html: String, daysBack: Int = 0) -> [ContributeData] {
let isoDateFormatter = ISO8601DateFormatter()
isoDateFormatter.formatOptions = [.withFullDate]

do {
let doc: Document = try SwiftSoup.parse(html)
let rects: Elements = try doc.getElementsByTag(ParseKeys.rect)
let tooltips: Elements = try doc.getElementsByTag(ParseKeys.tooltip)
let days: [Element] = rects.array().filter { $0.hasAttr(ParseKeys.date) }
let sortedDays = sortDaysByDate(days, with: isoDateFormatter)
let weekend = sortedDays.suffix(Consts.fetchCount)
let trimmedDays = daysBack > 0 ? sortedDays.dropLast(daysBack) : ArraySlice(sortedDays)
let weekend = trimmedDays.suffix(Consts.fetchCount)

var tooltipsTextById = [String: String]()
for tooltip in tooltips.array() {
Expand Down
1 change: 1 addition & 0 deletions Sources/Consts/Consts.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ enum Consts {
static let usernameDefaultKey = "username"
static let friendUsernameDefaultKey = "friend_username"
static let goalDefaultKey = "goal"
static let selfCompareOffsetDefaultKey = "self_compare_offset"
}
5 changes: 5 additions & 0 deletions Sources/Consts/Localized.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ enum Localized {
static let changeFriendUsername = NSLocalizedString("change_friend_username", comment: "Change friend username")
static let setFriendUsername = NSLocalizedString("set_friend_username", comment: "Set friend username")
static let removeFriendUsername = NSLocalizedString("remove_friend_username", comment: "Remove friend username")
static let setPastSelf = NSLocalizedString("set_past_self", comment: "Set past self comparison")
static let changePastSelf = NSLocalizedString("change_past_self", comment: "Change past self offset")
static let removePastSelf = NSLocalizedString("remove_past_self", comment: "Stop comparing with past self")
static let pastSelfInformation = NSLocalizedString("past_self_information", comment: "How many days ago to compare with")
static let withPastSelf = NSLocalizedString("with_past_self", comment: "\nvs me ${day} day(s) ago")
static let setGoal = NSLocalizedString("set_goal", comment: "Set goal")
static let help = NSLocalizedString("help", comment: "help")
static let textFieldPlaceholder = NSLocalizedString("textfield_placeholder", comment: "Github username")
Expand Down
5 changes: 5 additions & 0 deletions Supporting Files/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
"change_friend_username" = "🤝 Change Friend username";
"set_friend_username" = "🤝 Set Friend username";
"remove_friend_username" = "🙋‍♂️ Remove Friend username";
"set_past_self" = "⏪ Compare with past me";
"change_past_self" = "⏪ Change past me offset";
"remove_past_self" = "🙋‍♂️ Stop comparing with past me";
"past_self_information" = "How many days ago should we compare with?\n(1 = yesterday)";
"with_past_self" = "\nvs me ${day} day(s) ago";
"set_goal" = "🏁 Set Goal";
"help" = "🐛 Bug Report";
"auto_launch" = "Automatically start Jandi at login";
Expand Down
5 changes: 5 additions & 0 deletions Supporting Files/ko.lproj/Localizable.strings
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
"change_friend_username" = "🤝 친구 아이디 변경";
"set_friend_username" = "🤝 친구 아이디 설정";
"remove_friend_username" = "🙋‍♂️ 친구 아이디 제거";
"set_past_self" = "⏪ 과거의 나와 비교";
"change_past_self" = "⏪ 과거의 나 일수 변경";
"remove_past_self" = "🙋‍♂️ 과거의 나 비교 중지";
"past_self_information" = "며칠 전의 나와 비교할까요?\n(1 = 어제)";
"with_past_self" = "\n${day}일 전의 나와 비교";
"set_goal" = "🏁 목표 설정";
"help" = "🐛 버그 제보하기";
"auto_launch" = "재시작시 자동 실행";
Expand Down