Skip to content

Commit

Permalink
1.1 rc
Browse files Browse the repository at this point in the history
  • Loading branch information
sourcelocation committed Nov 26, 2022
1 parent ec739f1 commit a794dc0
Show file tree
Hide file tree
Showing 14 changed files with 137 additions and 67 deletions.
Binary file added .DS_Store
Binary file not shown.
18 changes: 14 additions & 4 deletions AirTroller.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,10 @@
isa = PBXGroup;
children = (
CE327915293049DE007B2098 /* AirTrollerApp.swift */,
CE327916293049DE007B2098 /* Alert.swift */,
CE32792C293155F0007B2098 /* Misc */,
CE32791E293049DE007B2098 /* Assets.xcassets */,
CE32791D293049DE007B2098 /* ContentView.swift */,
CE32791F293049DE007B2098 /* Extensions.swift */,
CE327914293049DE007B2098 /* ImagePickerView.swift */,
CE32791B293049DE007B2098 /* Preview Content */,
CE327913293049DE007B2098 /* RemoteLog.h */,
CE327917293049DE007B2098 /* trolldrop */,
CE327912293049DE007B2098 /* AirTroller-Bridging-Header.h */,
);
Expand All @@ -110,6 +107,17 @@
path = "Preview Content";
sourceTree = "<group>";
};
CE32792C293155F0007B2098 /* Misc */ = {
isa = PBXGroup;
children = (
CE327914293049DE007B2098 /* ImagePickerView.swift */,
CE327916293049DE007B2098 /* Alert.swift */,
CE32791F293049DE007B2098 /* Extensions.swift */,
CE327913293049DE007B2098 /* RemoteLog.h */,
);
path = Misc;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -323,6 +331,7 @@
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.education";
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Well, you've clicked this button to select photos, what did you exoect?";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
Expand Down Expand Up @@ -357,6 +366,7 @@
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.education";
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "Well, you've clicked this button to select photos, what did you exoect?";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "125AEEE4-CE9A-4F6D-AE97-4DE5654A7443"
type = "1"
version = "2.0">
</Bucket>
40 changes: 25 additions & 15 deletions AirTroller/AirTrollerApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,27 +13,37 @@ struct AirTrollerApp: App {
WindowGroup {
ContentView()
.onAppear {
// MARK: Check for new versions
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String, let url = URL(string: "https://api.github.com/repos/sourcelocation/AirTroller/releases/latest") {
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else { return }

if let json = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
if json["tag_name"] as? String != version {
UIApplication.shared.confirmAlert(title: "Update available", body: "A new AirTroller update is available, do you want to visit releases page?", onOK: {
UIApplication.shared.open(URL(string: "https://github.com/sourcelocation/AirTroller/releases/latest")!)
}, noCancel: false)
}
}
}
task.resume()
}
checkNewVersions()

// Clean up tmp dir
for url in (try? FileManager.default.contentsOfDirectory(at: FileManager.default.temporaryDirectory, includingPropertiesForKeys: nil)) ?? [] {
try? FileManager.default.removeItem(at: url)
}

// Check if user has root access
do {
try FileManager.default.contentsOfDirectory(at: URL(fileURLWithPath: "/var/mobile"), includingPropertiesForKeys: nil)
} catch {
UIApplication.shared.alert(body: "The app needs to be installed either using TrollStore or on Jailbroken devices error: \(error)", withButton: false)
}
}
}
}

func checkNewVersions() {
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String, let url = URL(string: "https://api.github.com/repos/sourcelocation/AirTroller/releases/latest") {
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else { return }

if let json = try? JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
if (json["tag_name"] as? String)?.compare(version, options: .numeric) == .orderedDescending {
UIApplication.shared.confirmAlert(title: "Update available", body: "A new AirTroller update is available, do you want to visit releases page?", onOK: {
UIApplication.shared.open(URL(string: "https://github.com/sourcelocation/AirTroller/releases/latest")!)
}, noCancel: false)
}
}
}
task.resume()
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions AirTroller/Assets.xcassets/AccentColor.colorset/Contents.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"colors" : [
{
"color" : {
"platform" : "ios",
"reference" : "systemBlueColor"
},
"idiom" : "universal"
}
],
Expand Down
Binary file modified AirTroller/Assets.xcassets/TrolledPerson.imageset/Group.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
126 changes: 78 additions & 48 deletions AirTroller/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ struct ContentView: View {
/// Custom selected image
@State var imageURL: URL?

private var gridItemLayout = [GridItem(.adaptive(minimum: 90, maximum: 110))]
private var gridItemLayout = [GridItem(.adaptive(minimum: 75, maximum: 100))]

var body: some View {
NavigationView {
Expand All @@ -35,12 +35,13 @@ struct ContentView: View {
ProgressView()
Text("Searching for devices...")
.foregroundColor(.secondary)
.padding()
}
} else {
VStack {
ScrollView {
LazyVGrid(columns: gridItemLayout, spacing: 8) {
ForEach(trollController.people, id: \.node) { p in
ForEach(trollController.people.sorted(by: { a, b in a.displayName ?? "" < b.displayName ?? "" }), id: \.node) { p in
PersonView(person: p, selected: $selectedPeople[p.node])
.environmentObject(trollController)
}
Expand All @@ -54,65 +55,57 @@ struct ContentView: View {
Slider(value: $rechargeDuration, in: 0...3.5)
Text(String(format: "%.1fs", rechargeDuration))
}
Button("Select custom image/file") {
showPicker()
}
.padding(16)
.frame(maxWidth: .infinity)
.background(Color(uiColor14: UIColor.secondarySystemFill ))
.cornerRadius(8)
.sheet(isPresented: $showingImagePicker) {
ImagePickerView(imageURL: $imageURL)
}

Button(!trollController.isRunning ? "Start trolling" : "Stop trolling") {
// guard selectedPeople.values.filter({ $0 == true }).count <= 2 else {
// UIApplication.shared.alert(title: "Cannot start, too many users selected", body: "AirTroller only allows trolling up to 2 people at a time. Please unselect some users to continue.")
// return
// }
// MARK: ~~people are physopaths~~ people ARE physopaths

Button(action: {
UIImpactFeedbackGenerator(style: .medium).impactOccurred() // mmm
if !trollController.isRunning {
UIApplication.shared.confirmAlert(title: "\(UIDevice.current.name)", body: "This is the current name of this device and the name people will see when receiving an AirDrop. Are you sure you want to continue?", onOK: {
if let imageURL = imageURL {
trollController.sharedURL = imageURL
}
trollController.startTrolling(shouldTrollHandler: { person in
return selectedPeople[person.node] ?? false // troll only selected people
}, eventHandler: { event in
switch event {
case .operationEvent(let event1):
if event1 == .canceled || event1 == .finished || event1 == .blocked {
totalAirDrops += 1
UISelectionFeedbackGenerator().selectionChanged()
}
case .cancelled:
totalAirDrops += 1
UISelectionFeedbackGenerator().selectionChanged()
}
}) // start trolling :troll:
trollController.isRunning.toggle()
}, noCancel: false)
if imageURL == nil {
showPicker()
} else {
trollController.stopTrollings()
trollController.isRunning.toggle()
imageURL = nil
}
}) {
Text(imageURL == nil ? "Select custom image/file" : imageURL!.lastPathComponent)
.padding(16)
.frame(maxWidth: .infinity)
.background(Color(uiColor14: UIColor.secondarySystemFill ))
.cornerRadius(8)
.sheet(isPresented: $showingImagePicker) {
ImagePickerView(imageURL: $imageURL)
}
}

Button(action: {
toggleTrollButtonTapped()
}) {
Text(!trollController.isRunning ? "Start trolling" : "Stop trolling")
.padding(16)
.frame(maxWidth: .infinity)
.background(Color.accentColor)
.foregroundColor(.white)
.cornerRadius(8)
}
.padding(16)
.frame(maxWidth: .infinity)
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
.padding()
}
}
}
.navigationTitle("AirTroller")
.toolbar {
ToolbarItemGroup(placement: .navigationBarLeading) {
Button(action: {
trollController.stopBrowser()
trollController.isRunning = false

selectedPeople = [:]
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
trollController.startBrowser()
}
}) {
Image(systemName: "arrow.clockwise")
}
}
ToolbarItemGroup(placement: .navigationBarTrailing) {
Button(action: {
UIImpactFeedbackGenerator(style: .light).impactOccurred() // mmm
openURL(URL(string: "https://github.com/sourcelocation/AirTroller")!)
}) {
Image("github")
Expand All @@ -121,6 +114,7 @@ struct ContentView: View {
.frame(height: 24)
}
Button(action: {
UIImpactFeedbackGenerator(style: .light).impactOccurred() // mmm
openURL(URL(string: "https://ko-fi.com/sourcelocation")!)
}) {
Image(systemName: "heart.fill")
Expand All @@ -133,6 +127,7 @@ struct ContentView: View {
}
.navigationViewStyle(StackNavigationViewStyle())
.onAppear {
// Start searching nodes
trollController.startBrowser()
}
.onChange(of: rechargeDuration) { newValue in
Expand All @@ -151,6 +146,41 @@ struct ContentView: View {
}
}

func toggleTrollButtonTapped() {
UIImpactFeedbackGenerator(style: .medium).impactOccurred() // mmm

guard selectedPeople.values.filter({ $0 == true }).count > 0 else {
UIApplication.shared.alert(title: "No people selected", body: "Select users by tapping on them.")
return
}

if !trollController.isRunning {
UIApplication.shared.confirmAlert(title: "\(UIDevice.current.name)", body: "This is the current name of this device and the name people will see when receiving an AirDrop. Are you sure you want to continue?", onOK: {
if let imageURL = imageURL {
trollController.sharedURL = imageURL
}
trollController.startTrolling(shouldTrollHandler: { person in
return selectedPeople[person.node] ?? false // troll only selected people
}, eventHandler: { event in
switch event {
case .operationEvent(let event1):
if event1 == .canceled || event1 == .finished || event1 == .blocked {
totalAirDrops += 1
UISelectionFeedbackGenerator().selectionChanged()
}
case .cancelled:
totalAirDrops += 1
UISelectionFeedbackGenerator().selectionChanged()
}
}) // start trolling :troll:
trollController.isRunning.toggle()
}, noCancel: false)
} else {
trollController.stopTrollings()
trollController.isRunning.toggle()
}
}

struct PersonView: View {
@State var person: TrollController.Person
@Binding var selected: Bool?
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
4 changes: 4 additions & 0 deletions AirTroller/trolldrop/TrollController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,9 @@ public class TrollController: ObservableObject {
// Cancel pending operations.
stopTrollings()

// Remove all known people
people = []

// Invalidate the browser.
TDKSFBrowserInvalidate(browser!)
browser = nil
Expand Down Expand Up @@ -211,6 +214,7 @@ public class TrollController: ObservableObject {
self?.troll(node: node) // troll again :troll:
}
}
trollings[node] = .workItem(workItem)
// wait for airdrop to appear on target device. afaik there isn't a way to know when the alert appeared.
DispatchQueue.main.asyncAfter(deadline: .now() + rechargeDuration, execute: workItem) // rechargeDuration is controlled via UI
default:
Expand Down
6 changes: 6 additions & 0 deletions entitlements.plist
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,11 @@
<string>IOHDIXControllerUserClient</string>
<string>IOSurfaceRootUserClient</string>
</array>
<key>com.apple.private.persona-mgmt</key>
<true/>
<key>com.apple.private.security.system-application</key>
<true/>
<key>com.apple.managedconfiguration.profiled-access</key>
<true/>
</dict>
</plist>

0 comments on commit a794dc0

Please sign in to comment.