Skip to content

Commit 513b7fa

Browse files
committed
Initial implementation of referrals
1 parent 9412d6e commit 513b7fa

File tree

89 files changed

+25691
-17786
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

89 files changed

+25691
-17786
lines changed

Jotify.xcodeproj/project.pbxproj

+8
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@
6767
F6B9D4CA25B629C800A0446C /* Double+Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6B9D4C925B629C800A0446C /* Double+Date.swift */; };
6868
F6C06D542837108B005AED28 /* DetailOnboardingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6C06D532837108B005AED28 /* DetailOnboardingController.swift */; };
6969
F6C06D5628371416005AED28 /* WelcomeViewOnboardingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6C06D5528371416005AED28 /* WelcomeViewOnboardingController.swift */; };
70+
F6C06D58283833A8005AED28 /* ReferralManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6C06D57283833A8005AED28 /* ReferralManager.swift */; };
71+
F6C06D5A283B0E23005AED28 /* ReferralSettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6C06D59283B0E23005AED28 /* ReferralSettingsController.swift */; };
7072
F6CF5DDF25DAEF2F006E576E /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F6CF5DDE25DAEF2F006E576E /* CloudKit.framework */; };
7173
F6CF5DF325DAF38D006E576E /* Jotify.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = F6CF5DF125DAF38D006E576E /* Jotify.xcdatamodeld */; };
7274
F6D2771225C8C00E00ECFCCC /* SettingsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F6D2771125C8C00E00ECFCCC /* SettingsCell.swift */; };
@@ -168,6 +170,8 @@
168170
F6B9D4C925B629C800A0446C /* Double+Date.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+Date.swift"; sourceTree = "<group>"; };
169171
F6C06D532837108B005AED28 /* DetailOnboardingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailOnboardingController.swift; sourceTree = "<group>"; };
170172
F6C06D5528371416005AED28 /* WelcomeViewOnboardingController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WelcomeViewOnboardingController.swift; sourceTree = "<group>"; };
173+
F6C06D57283833A8005AED28 /* ReferralManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferralManager.swift; sourceTree = "<group>"; };
174+
F6C06D59283B0E23005AED28 /* ReferralSettingsController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReferralSettingsController.swift; sourceTree = "<group>"; };
171175
F6CF5DDC25DAEF2B006E576E /* Jotify.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Jotify.entitlements; sourceTree = "<group>"; };
172176
F6CF5DDE25DAEF2F006E576E /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; };
173177
F6CF5DF225DAF38D006E576E /* Jotify.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Jotify.xcdatamodel; sourceTree = "<group>"; };
@@ -241,6 +245,7 @@
241245
F67F002925B32F5B00313D61 /* NoteCollection.swift */,
242246
F67F002625B32EEC00313D61 /* DataManager.swift */,
243247
F67F002325B32EE600313D61 /* AuthManager.swift */,
248+
F6C06D57283833A8005AED28 /* ReferralManager.swift */,
244249
);
245250
path = Firebase;
246251
sourceTree = "<group>";
@@ -442,6 +447,7 @@
442447
F61580172697D3BA00ABB6F6 /* GeneralSettingsController.swift */,
443448
F67AA6CF2783E6FB004BD86E /* CustomizationSettingsController.swift */,
444449
F6DFF0C525C8FF9D004D6468 /* AccountSettingsController.swift */,
450+
F6C06D59283B0E23005AED28 /* ReferralSettingsController.swift */,
445451
);
446452
path = Settings;
447453
sourceTree = "<group>";
@@ -611,6 +617,7 @@
611617
F62209442602B07A001DFAC1 /* SceneDelegate+Gestures.swift in Sources */,
612618
F69389E32699183E00EF3EED /* SetupController.swift in Sources */,
613619
F67F003825B32F7900313D61 /* NoteCollectionController.swift in Sources */,
620+
F6C06D58283833A8005AED28 /* ReferralManager.swift in Sources */,
614621
F680C9CD269A957000D86EF3 /* ReminderController.swift in Sources */,
615622
F6A5F9462604E5F200E46105 /* DismissKeyboardSwiftUI.swift in Sources */,
616623
F678330E2640F4D6005429FF /* NoteCollectionController+Search.swift in Sources */,
@@ -624,6 +631,7 @@
624631
F69389D42699158A00EF3EED /* RecentNoteWidget.intentdefinition in Sources */,
625632
F6CF5DF325DAF38D006E576E /* Jotify.xcdatamodeld in Sources */,
626633
F622093D2602B00E001DFAC1 /* LogInView.swift in Sources */,
634+
F6C06D5A283B0E23005AED28 /* ReferralSettingsController.swift in Sources */,
627635
F6F185B225C86ABF001FD5FA /* MasterSettingsController.swift in Sources */,
628636
F66F5C4B267FE3BD004CB9F1 /* GradientAnimator.swift in Sources */,
629637
F6425CC12680D286008C03A2 /* UIColor+StringInterpretor.swift in Sources */,

Jotify.xcodeproj/xcuserdata/harrisonleath.xcuserdatad/xcschemes/xcschememanagement.plist

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<key>RecentNoteWidgetExtension.xcscheme_^#shared#^_</key>
1313
<dict>
1414
<key>orderHint</key>
15-
<integer>30</integer>
15+
<integer>31</integer>
1616
</dict>
1717
</dict>
1818
<key>SuppressBuildableAutocreation</key>

Jotify/Controller/Authentication/AuthenticationController.swift

+7-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,13 @@ class AuthenticationController: UIViewController {
2626
} else {
2727
AnalyticsManager.logEvent(named: "sign_up", description: "sign_up")
2828
DataManager.createUserSettings { (success) in }
29-
//change rootViewController to PageViewController w/ animation
29+
//check if there was a referral
30+
if let id = UserDefaults.standard.string(forKey: "referralId") {
31+
//there was a referral, id != nil
32+
ReferralManager().grantReferralCredit(referrerId: id)
33+
}
34+
//create referral link and upload it to settings doc in Firestore
35+
ReferralManager().createReferralLink()
3036
self.setRootViewController(duration: 0.2, vc: PageBoyController())
3137
}
3238
}

Jotify/Controller/PageBoyController.swift

+14-4
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,12 @@ class PageBoyController: PageboyViewController, PageboyViewControllerDataSource
7070
}
7171

7272
@objc func disableSwipe(notification: Notification){
73-
print("Swipe is disabled")
73+
// print("Swipe is disabled")
7474
self.isScrollEnabled = false
7575
}
7676

7777
@objc func enableSwipe(notification: Notification){
78-
print("Swipe is enabled")
78+
// print("Swipe is enabled")
7979
self.isScrollEnabled = true
8080
}
8181

@@ -89,8 +89,18 @@ class PageBoyController: PageboyViewController, PageboyViewControllerDataSource
8989
User.settings = settings
9090
print("Has migrated: \(String(describing: User.settings?.hasMigrated))")
9191
if !(settings!.hasMigrated) && !UserDefaults.standard.bool(forKey: "hasMigrated") {
92-
//notify when notes are fetched from context, CloudKit
93-
NotificationCenter.default.addObserver(self, selector: #selector(self.migrateDataFromCloudKit), name: .NSManagedObjectContextObjectsDidChange, object: MigrationHandler().context)
92+
//ask user if they want to migrate notes
93+
let alertController = UIAlertController(title: "Migrate Notes", message: "Jotify found notes from a previous version. Would you like to migrate your notes, so you can continue to access them?", preferredStyle: .alert)
94+
alertController.addAction(UIAlertAction(title: "No", style: .destructive, handler: {(action) in
95+
//set these values, so this prompt does not appear on every launch
96+
UserDefaults.standard.setValue(true, forKey: "hasMigrated")
97+
DataManager.updateUserSettings(setting: "hasMigrated", value: true) { (success) in }
98+
}))
99+
alertController.addAction(UIAlertAction(title: "Yes", style: .default, handler: {(action) in
100+
//notify when notes are fetched from context, CloudKit
101+
NotificationCenter.default.addObserver(self, selector: #selector(self.migrateDataFromCloudKit), name: .NSManagedObjectContextObjectsDidChange, object: MigrationHandler().context)
102+
}))
103+
self.present(alertController, animated: true, completion: nil)
94104
}
95105
}
96106
}

Jotify/Controller/Settings/MasterSettingsController.swift

+9-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class MasterSettingsController: SettingsController {
1212
override func viewDidLoad() {
1313
super.viewDidLoad()
1414
super.sections = ["General"]
15-
super.section1 = ["General", "Customization", "Account"]
15+
super.section1 = ["General", "Customization", "Account", "Referrals"]
1616
navigationItem.title = "Settings"
1717

1818
//disable swiping to create a new note when changing settings
@@ -56,6 +56,14 @@ class MasterSettingsController: SettingsController {
5656
} else if UIDevice.current.userInterfaceIdiom == .phone {
5757
navigationController?.pushViewController(vc, animated: true)
5858
}
59+
case 3:
60+
let vc = ReferralSettingsController()
61+
if UIDevice.current.userInterfaceIdiom == .pad {
62+
vc.modalPresentationStyle = .formSheet
63+
present(vc, animated: true, completion: nil)
64+
} else if UIDevice.current.userInterfaceIdiom == .phone {
65+
navigationController?.pushViewController(vc, animated: true)
66+
}
5967
default:
6068
print("")
6169
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
//
2+
// ReferralSettingsController.swift
3+
// Jotify
4+
//
5+
// Created by Harrison Leath on 5/22/22.
6+
//
7+
8+
import UIKit
9+
import MessageUI
10+
11+
class ReferralSettingsController: UIViewController, MFMessageComposeViewControllerDelegate {
12+
13+
let detailText: UITextView = {
14+
let tv = UITextView()
15+
tv.font = UIFont.systemFont(ofSize: 18, weight: .regular)
16+
tv.textAlignment = .center
17+
tv.backgroundColor = .clear
18+
tv.isUserInteractionEnabled = false
19+
tv.translatesAutoresizingMaskIntoConstraints = false
20+
return tv
21+
}()
22+
23+
lazy var nextButton: UIButton = {
24+
let button = UIButton()
25+
button.setTitleColor(.white, for: .normal)
26+
button.backgroundColor = UIColor.jotifyBlue
27+
button.layer.cornerRadius = 10
28+
button.translatesAutoresizingMaskIntoConstraints = false
29+
button.addTarget(self, action: #selector(shareReferral), for: .touchUpInside)
30+
button.setTitle("Invite Someone", for: .normal)
31+
return button
32+
}()
33+
34+
let wrapper: UIView = {
35+
let view = UIView()
36+
view.backgroundColor = .clear
37+
view.translatesAutoresizingMaskIntoConstraints = false
38+
return view
39+
}()
40+
41+
//press a button to send referral link
42+
43+
override func viewDidLoad() {
44+
super.viewDidLoad()
45+
46+
view.backgroundColor = ColorManager.bgColor
47+
48+
let referrals = User.settings?.referrals ?? 0
49+
50+
detailText.text = "You have \(referrals) referrals. Once you reach 3 referrals, Jotify premium is given automatically!"
51+
52+
view.addSubview(wrapper)
53+
view.addSubview(nextButton)
54+
55+
wrapper.addSubview(detailText)
56+
57+
wrapper.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
58+
wrapper.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
59+
wrapper.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: 0.85).isActive = true
60+
wrapper.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.80).isActive = true
61+
62+
63+
detailText.centerXAnchor.constraint(equalTo: wrapper.centerXAnchor).isActive = true
64+
detailText.topAnchor.constraint(equalTo: wrapper.centerYAnchor).isActive = true
65+
detailText.heightAnchor.constraint(equalToConstant: 400).isActive = true
66+
67+
//to make the text fit relatively ok on iPad
68+
if view.bounds.width * 0.85 > 500 {
69+
detailText.widthAnchor.constraint(equalToConstant: 500).isActive = true
70+
} else {
71+
detailText.widthAnchor.constraint(equalTo: wrapper.widthAnchor).isActive = true
72+
}
73+
74+
nextButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
75+
nextButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -75).isActive = true
76+
nextButton.widthAnchor.constraint(equalToConstant: 250).isActive = true
77+
nextButton.heightAnchor.constraint(equalToConstant: 60).isActive = true
78+
}
79+
80+
@objc func shareReferral() {
81+
let invitationLink = User.settings?.referralLink
82+
let subject = "You should start using Jotify! Use my referreral link: \(invitationLink ?? "nil")"
83+
84+
let messageComposer = MFMessageComposeViewController()
85+
messageComposer.messageComposeDelegate = self
86+
messageComposer.body = subject
87+
88+
if MFMessageComposeViewController.canSendText() {
89+
present(messageComposer, animated: true)
90+
} else {
91+
//TODO: Copy the link to the clipboard and present alert to user telling them this.
92+
UIPasteboard.general.string = subject
93+
let alertController = UIAlertController(title: "Unable to Send", message: "You cannot message from this device, so Jotify copied the referral link to your clipboard.", preferredStyle: .alert)
94+
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: {(action) in }))
95+
self.present(alertController, animated: true, completion: nil)
96+
}
97+
98+
self.playHapticFeedback()
99+
}
100+
101+
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
102+
if result == .sent {
103+
dismiss(animated: true)
104+
} else if result == .cancelled {
105+
dismiss(animated: true)
106+
} else {
107+
dismiss(animated: true)
108+
//copy link to clipboard and alert user
109+
let invitationLink = User.settings?.referralLink
110+
UIPasteboard.general.string = "You should start using Jotify! Use my referreral link: \(invitationLink ?? "nil")"
111+
let alertController = UIAlertController(title: "Unable to Send", message: "The message failed to send, so Jotify copied the link to your clipboard.", preferredStyle: .alert)
112+
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: {(action) in }))
113+
self.present(alertController, animated: true, completion: nil)
114+
}
115+
}
116+
}

Jotify/Controller/SetupController.swift

+5-2
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ class SetupController {
3131
let domain = Bundle.main.bundleIdentifier!
3232
UserDefaults.standard.removePersistentDomain(forName: domain)
3333
UserDefaults.standard.synchronize()
34-
print(Array(UserDefaults.standard.dictionaryRepresentation().keys).count)
3534

3635
UserDefaults.standard.register(defaults: [
3736
"hasMigrated": false,
@@ -41,6 +40,8 @@ class SetupController {
4140
"useBiometrics": false,
4241
"placeholder": "Tap to start typing or swipe left to right for saved notes...",
4342
"defaultView": 0,
43+
"referrals": 0,
44+
"referralLink": "",
4445
])
4546
}
4647

@@ -67,16 +68,18 @@ class SetupController {
6768
if previousVersion == currentVersion {
6869
// same version, no update
6970
print("same version")
71+
//TODO: Before launching the beta enable this to wipe all settings and start over...
72+
setupDefaults()
7073

7174
} else {
7275
if previousVersion != nil {
7376
// new version
7477
print("new version")
7578
//show onboarding when user updates to 2.0.0
79+
//TODO: Change this for any version after 2.0.0
7680
SetupController.firstLauch = true
7781
setupWidget()
7882
setupDefaults()
79-
8083
} else {
8184
// first launch
8285
print("first launch")

Jotify/GradientAnimator/ColorManager.swift

-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ class ColorManager {
2020
//fill an array of indexes that correspond to the array as a parameter
2121
//remove elements from indexes array as they are selected from parameter array
2222
//repeat when indexes is empty
23-
//TODO:: FIX THIS METHOD, DOESNT WORK
2423
@discardableResult static func setNoteColor() -> UIColor {
2524
let count = GradientThemes.All.colors().count
2625
if ColorManager.indexes.count == 0 {

Jotify/Info.plist

+13
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,19 @@
1616
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
1717
<key>CFBundleShortVersionString</key>
1818
<string>$(MARKETING_VERSION)</string>
19+
<key>CFBundleURLTypes</key>
20+
<array>
21+
<dict>
22+
<key>CFBundleTypeRole</key>
23+
<string>Editor</string>
24+
<key>CFBundleURLName</key>
25+
<string>Bundle ID</string>
26+
<key>CFBundleURLSchemes</key>
27+
<array>
28+
<string>com.austinleath.Jotify</string>
29+
</array>
30+
</dict>
31+
</array>
1932
<key>CFBundleVersion</key>
2033
<string>$(CURRENT_PROJECT_VERSION)</string>
2134
<key>LSRequiresIPhoneOS</key>

Jotify/Jotify.entitlements

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88
<array>
99
<string>Default</string>
1010
</array>
11+
<key>com.apple.developer.associated-domains</key>
12+
<array>
13+
<string>applinks:jotify.page.link</string>
14+
</array>
1115
<key>com.apple.developer.icloud-container-identifiers</key>
1216
<array>
1317
<string>iCloud.com.austinleath.Jotify</string>

Jotify/Model/Firebase/DataManager.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ class DataManager {
2121
"placeholder": "Tap to start typing or swipe left to right for saved notes...",
2222
"hasMigrated": false,
2323
"defaultView": 0,
24+
"referrals": 0,
25+
"referralLink": "",
2426
]) { (error) in
2527
if let error = error {
2628
print("Error deleting document: \(error.localizedDescription)")
@@ -42,7 +44,7 @@ class DataManager {
4244
completionHandler(nil, false)
4345
} else {
4446
print("Firebase settings retrieved")
45-
let settings = Settings(multilineInputEnabled: snapshot?.get("multilineInputEnabled") as? Bool ?? false, deleteOldNotes: snapshot?.get("deleteOldNotes") as? Bool ?? false, useHaptics: snapshot?.get("useHaptics") as? Bool ?? true, useBiometrics: snapshot?.get("useBiometrics") as? Bool ?? false, placeholder: snapshot?.get("placeholder") as? String ?? "Tap to start typing or swipe left to right for saved notes...", defaultView: snapshot?.get("defaultView") as? Int ?? 0, hasMigrated: snapshot?.get("hasMigrated") as? Bool ?? false)
47+
let settings = Settings(multilineInputEnabled: snapshot?.get("multilineInputEnabled") as? Bool ?? false, deleteOldNotes: snapshot?.get("deleteOldNotes") as? Bool ?? false, useHaptics: snapshot?.get("useHaptics") as? Bool ?? true, useBiometrics: snapshot?.get("useBiometrics") as? Bool ?? false, placeholder: snapshot?.get("placeholder") as? String ?? "Tap to start typing or swipe left to right for saved notes...", defaultView: snapshot?.get("defaultView") as? Int ?? 0, hasMigrated: snapshot?.get("hasMigrated") as? Bool ?? false, referrals: snapshot?.get("referrals") as? Int ?? 0, referralLink: snapshot?.get("referralLink") as? String ?? "")
4648
completionHandler(settings, true)
4749
}
4850
}

0 commit comments

Comments
 (0)