Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Widget bundle #2

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
Binary file modified .DS_Store
Binary file not shown.
29 changes: 29 additions & 0 deletions RepoWatcher.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
E617C6D12D5F1E3F002C8007 /* RepoWatcherWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = RepoWatcherWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
E617C6D32D5F1E40002C8007 /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; };
E617C6D52D5F1E40002C8007 /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; };
E61EDADA2D64F19F00202BF2 /* RepoWatcherWidgetExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = RepoWatcherWidgetExtension.entitlements; sourceTree = "<group>"; };
E6C4DE8D2D64BE0C009CDEE4 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */

/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
Expand All @@ -54,17 +56,35 @@
E617C6F82D5F285A002C8007 /* Exceptions for "RepoWatcher" folder in "RepoWatcherWidgetExtension" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
"Extensions/UserDefaults+Ext.swift",
Models/Contributor.swift,
Models/Repository.swift,
Resources/Secrets.plist,
Services/NetworkManager.swift,
);
target = E617C6D02D5F1E3F002C8007 /* RepoWatcherWidgetExtension */;
};
E6C4DE852D64BD05009CDEE4 /* Exceptions for "RepoWatcherWidget" folder in "RepoWatcher" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Intents/SelectSingleRepo.swift,
);
target = E617C6BB2D5F1E04002C8007 /* RepoWatcher */;
};
E6C4DE872D64BD33009CDEE4 /* Exceptions for "RepoWatcher" folder in "RepoWatcher" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Info.plist,
);
target = E617C6BB2D5F1E04002C8007 /* RepoWatcher */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */

/* Begin PBXFileSystemSynchronizedRootGroup section */
E617C6BE2D5F1E04002C8007 /* RepoWatcher */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
E6C4DE872D64BD33009CDEE4 /* Exceptions for "RepoWatcher" folder in "RepoWatcher" target */,
E617C6F82D5F285A002C8007 /* Exceptions for "RepoWatcher" folder in "RepoWatcherWidgetExtension" target */,
);
path = RepoWatcher;
Expand All @@ -73,6 +93,7 @@
E617C6D72D5F1E40002C8007 /* RepoWatcherWidget */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
E6C4DE852D64BD05009CDEE4 /* Exceptions for "RepoWatcherWidget" folder in "RepoWatcher" target */,
E617C6E22D5F1E42002C8007 /* Exceptions for "RepoWatcherWidget" folder in "RepoWatcherWidgetExtension" target */,
);
path = RepoWatcherWidget;
Expand Down Expand Up @@ -103,6 +124,7 @@
E617C6B32D5F1E04002C8007 = {
isa = PBXGroup;
children = (
E61EDADA2D64F19F00202BF2 /* RepoWatcherWidgetExtension.entitlements */,
E617C6BE2D5F1E04002C8007 /* RepoWatcher */,
E617C6D72D5F1E40002C8007 /* RepoWatcherWidget */,
E617C6D22D5F1E40002C8007 /* Frameworks */,
Expand All @@ -124,6 +146,7 @@
children = (
E617C6D32D5F1E40002C8007 /* WidgetKit.framework */,
E617C6D52D5F1E40002C8007 /* SwiftUI.framework */,
E6C4DE8D2D64BE0C009CDEE4 /* Intents.framework */,
);
name = Frameworks;
sourceTree = "<group>";
Expand Down Expand Up @@ -382,12 +405,14 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = RepoWatcher/RepoWatcher.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"RepoWatcher/Preview Content\"";
DEVELOPMENT_TEAM = 3M7PED79H5;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = RepoWatcher/Info.plist;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
Expand All @@ -411,12 +436,14 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = RepoWatcher/RepoWatcher.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"RepoWatcher/Preview Content\"";
DEVELOPMENT_TEAM = 3M7PED79H5;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = RepoWatcher/Info.plist;
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
Expand All @@ -440,6 +467,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = RepoWatcherWidgetExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 3M7PED79H5;
Expand Down Expand Up @@ -467,6 +495,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground;
CODE_SIGN_ENTITLEMENTS = RepoWatcherWidgetExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = 3M7PED79H5;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "46244770-E87D-443C-83DD-B31B7C573E08"
type = "1"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "BF3BAC1D-4693-4157-813D-8E7E96F57494"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "RepoWatcherWidget/Views/CompactEntryView.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "17"
endingLineNumber = "17"
landmarkName = "DoubleRepoEntryView"
landmarkType = "14">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,17 @@
<key>RepoWatcher.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
<integer>1</integer>
</dict>
<key>RepoWatcherIntents.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>2</integer>
</dict>
<key>RepoWatcherWidgetExtension.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>1</integer>
<integer>0</integer>
</dict>
</dict>
</dict>
Expand Down
Binary file modified RepoWatcher/.DS_Store
Binary file not shown.
24 changes: 0 additions & 24 deletions RepoWatcher/ContentView.swift

This file was deleted.

38 changes: 38 additions & 0 deletions RepoWatcher/Extensions/UserDefaults+Ext.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//
// UserDefaults+Ext.swift
// RepoWatcher
//
// Created by Michael Martell on 2/18/25.
//

import Foundation

extension UserDefaults {
private static let suiteName = "group.com.michaelMartell.RepoWatcher"

static var shared: UserDefaults {
guard let defaults = UserDefaults(suiteName: suiteName) else {
print("⚠️ Failed to access shared defaults with suite: \(suiteName)")
return .standard
}
print("Debug: Accessed shared defaults with suite: \(suiteName)")
return defaults
}

static let repoKey = "repos"
static let githubKey = "githubKey"

// Helper method to verify setup
static func verifySharedAccess() {
let defaults = UserDefaults.shared
print("Debug: Shared UserDefaults verification:")
print("Debug: - Can access token: \(defaults.string(forKey: githubKey) != nil)")
print("Debug: - Can access repos: \(defaults.array(forKey: repoKey) != nil)")
}
}

enum UserDefaultsError: Error {
case failedToSetValue
case failedToGetValue
case retrievalFailed
}
14 changes: 14 additions & 0 deletions RepoWatcher/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>INIntentsSupported</key>
<array>
<string>SelectSingleRepo</string>
</array>
<key>NSUserActivityTypes</key>
<array>
<string>SelectSingleRepoIntent</string>
</array>
</dict>
</plist>
24 changes: 24 additions & 0 deletions RepoWatcher/Models/Contributor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,27 @@
//

import Foundation

struct Contributor: Identifiable {
let id = UUID()
let login: String
let avatarUrl: String
let contributions: Int
var avatarData: Data
}

extension Contributor {
struct CodingData: Decodable {
let login: String
let avatarUrl: String
let contributions: Int

var contributor: Contributor {
Contributor(
login: login,
avatarUrl: avatarUrl,
contributions: contributions,
avatarData: Data())
}
}
}
1 change: 1 addition & 0 deletions RepoWatcher/Models/Repository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ struct Repository {
let forks: Int
let pushedAt: String
var avatarData: Data
var contributors: [Contributor] = []
}

extension Repository {
Expand Down
10 changes: 10 additions & 0 deletions RepoWatcher/RepoWatcher.entitlements
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.com.michaelMartell.RepoWatcher</string>
</array>
</dict>
</plist>
59 changes: 56 additions & 3 deletions RepoWatcher/Services/NetworkManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@ class NetworkManager {

// Access token from configuration
private var token: String? {
let token = getToken()
print("Debug: GitHub token found: \(token != nil)")
return token
// Check shared UserDefaults first
if let sharedDefaults = UserDefaults(suiteName: "group.com.michaelMartell.RepoWatcher"),
let userToken = sharedDefaults.string(forKey: "githubKey"),
!userToken.isEmpty {
return userToken
}

// Fall back to Secrets.plist
return getToken()
}

private func getToken() -> String? {
Expand Down Expand Up @@ -102,6 +108,50 @@ class NetworkManager {
}
}

func getContributors(atUrl urlString: String) async throws -> [Contributor] {
guard let url = URL(string: urlString) else {
throw NetworkError.invalidURL
}

var request = URLRequest(url: url)
request.httpMethod = "GET"

if let token = token {
request.addValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
}
request.addValue("application/vnd.github.v3+json", forHTTPHeaderField: "Accept")

let (data, response) = try await URLSession.shared.data(for: request)

guard let httpResponse = response as? HTTPURLResponse else {
throw NetworkError.invalidResponse
}

switch httpResponse.statusCode {
case 200:
do {
let codingData = try decoder.decode([Contributor.CodingData].self, from: data)
let contributors = codingData.map { $0.contributor}
return contributors
} catch {
print("❌ Decoding error: \(error)")
throw NetworkError.invalidRepoData
}
case 401:
print("⚠️ Unauthorized - API key might be missing or invalid")
throw NetworkError.unauthorized
case 403:
print("⚠️ Forbidden - Check API rate limits or token permissions")
throw NetworkError.forbidden
case 404:
print("⚠️ Repository not found")
throw NetworkError.notFound
default:
throw NetworkError.invalidResponse
}
}


func downloadImageData(from urlString: String) async throws -> Data? {
guard let url = URL(string: urlString) else { return nil }

Expand Down Expand Up @@ -169,7 +219,10 @@ enum NetworkError: Error {
}

enum RepoURL {
static let prefix = "https://api.github.com/repos/"
static let monthlyWidgetFull = "https://api.github.com/repos/gold240sx/Monthly-Widget-Full"
static let davidsGaragePro = "https://api.github.com/repos/Gold240sx/DGP_Prod"
static let portfolio = "https://api.github.com/repos/Gold240sx/portfolio_2025"
static let swiftNews = "https://api.github.com/repos/sallen0400/swift-news"
static let google = "https://api.github.com/repos/google/GoogleSignIn-iOS"
}
Loading