Skip to content
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
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Deepa - iOSConfSG app in SwiftUI edition

Hi, Deepa is a work in progress to rewrite the iOS Conf SG app, slated to be used in our upcoming conference: 12-13 January 2023
For more info about the conference, visit https://iosconf.sg

## Contributions

The following contributions are accepted:

1. Show the conference Schedule for both days
2. Handle a talk detail
3. Handle a feedback submission
3. Show the workshop schedule

## Build the app

You need at least, Xcode 14 to build the app locally. It has been setup with Apollo Graphql iOS library to fetch the Schedule using a subscription

55 changes: 51 additions & 4 deletions deepa.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
5A936E6328D5AECA00C6065B /* WorkshopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A936E6228D5AECA00C6065B /* WorkshopView.swift */; };
5A936E6828D5AF2900C6065B /* InfoView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A936E6728D5AF2900C6065B /* InfoView.swift */; };
5A936E6A28D5AF4100C6065B /* NewsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A936E6928D5AF4100C6065B /* NewsView.swift */; };
5A936E6D28D6144200C6065B /* Talk.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A936E6C28D6144200C6065B /* Talk.swift */; };
5A936E6F28D6148600C6065B /* Speaker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5A936E6E28D6148600C6065B /* Speaker.swift */; };
5A936E7228D6234A00C6065B /* Atlantis in Frameworks */ = {isa = PBXBuildFile; productRef = 5A936E7128D6234A00C6065B /* Atlantis */; };
972E5C1C2913D0AF0021AEF2 /* WorkshopDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 972E5C1B2913D0AF0021AEF2 /* WorkshopDetailsView.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -65,6 +69,10 @@
5A936E6228D5AECA00C6065B /* WorkshopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkshopView.swift; sourceTree = "<group>"; };
5A936E6728D5AF2900C6065B /* InfoView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoView.swift; sourceTree = "<group>"; };
5A936E6928D5AF4100C6065B /* NewsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewsView.swift; sourceTree = "<group>"; };
5A936E6C28D6144200C6065B /* Talk.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Talk.swift; sourceTree = "<group>"; };
5A936E6E28D6148600C6065B /* Speaker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Speaker.swift; sourceTree = "<group>"; };
5A936E7328D623F500C6065B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
972E5C1B2913D0AF0021AEF2 /* WorkshopDetailsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkshopDetailsView.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -73,6 +81,7 @@
buildActionMask = 2147483647;
files = (
5A936E5928D5A8B200C6065B /* Apollo in Frameworks */,
5A936E7228D6234A00C6065B /* Atlantis in Frameworks */,
5A936E5B28D5A8B200C6065B /* ApolloWebSocket in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -117,11 +126,13 @@
5A936E1C28D377C200C6065B /* deepa */ = {
isa = PBXGroup;
children = (
5A936E7328D623F500C6065B /* Info.plist */,
5A936E4E28D5961500C6065B /* schema.json */,
5A936E5028D5967300C6065B /* api.graphql */,
5A936E5228D596D300C6065B /* API.swift */,
5A936E1D28D377C200C6065B /* deepaApp.swift */,
5A936E1F28D377C200C6065B /* ContentView.swift */,
5A936E6B28D6143100C6065B /* Models */,
5A936E5C28D5ADC400C6065B /* Schedule */,
5A936E6128D5AEB100C6065B /* Workshop */,
5A936E6428D5AEED00C6065B /* News */,
Expand Down Expand Up @@ -172,6 +183,7 @@
children = (
5A936E5D28D5ADDC00C6065B /* ScheduleView.swift */,
5A936E5F28D5ADE700C6065B /* ScheduleViewModel.swift */,
972E5C1B2913D0AF0021AEF2 /* WorkshopDetailsView.swift */,
);
path = Schedule;
sourceTree = "<group>";
Expand Down Expand Up @@ -200,6 +212,15 @@
path = Info;
sourceTree = "<group>";
};
5A936E6B28D6143100C6065B /* Models */ = {
isa = PBXGroup;
children = (
5A936E6C28D6144200C6065B /* Talk.swift */,
5A936E6E28D6148600C6065B /* Speaker.swift */,
);
path = Models;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand All @@ -220,6 +241,7 @@
packageProductDependencies = (
5A936E5828D5A8B200C6065B /* Apollo */,
5A936E5A28D5A8B200C6065B /* ApolloWebSocket */,
5A936E7128D6234A00C6065B /* Atlantis */,
);
productName = deepa;
productReference = 5A936E1A28D377C200C6065B /* deepa.app */;
Expand Down Expand Up @@ -295,6 +317,7 @@
mainGroup = 5A936E1128D377C200C6065B;
packageReferences = (
5A936E5728D5A8B200C6065B /* XCRemoteSwiftPackageReference "apollo-ios" */,
5A936E7028D6234A00C6065B /* XCRemoteSwiftPackageReference "atlantis" */,
);
productRefGroup = 5A936E1B28D377C200C6065B /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -363,8 +386,11 @@
files = (
5A936E6828D5AF2900C6065B /* InfoView.swift in Sources */,
5A936E5E28D5ADDC00C6065B /* ScheduleView.swift in Sources */,
972E5C1C2913D0AF0021AEF2 /* WorkshopDetailsView.swift in Sources */,
5A936E5628D5974900C6065B /* NetworkManager.swift in Sources */,
5A936E6D28D6144200C6065B /* Talk.swift in Sources */,
5A936E6A28D5AF4100C6065B /* NewsView.swift in Sources */,
5A936E6F28D6148600C6065B /* Speaker.swift in Sources */,
5A936E6028D5ADE700C6065B /* ScheduleViewModel.swift in Sources */,
5A936E6328D5AECA00C6065B /* WorkshopView.swift in Sources */,
5A936E2028D377C200C6065B /* ContentView.swift in Sources */,
Expand Down Expand Up @@ -456,6 +482,8 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -508,6 +536,8 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MACOSX_DEPLOYMENT_TARGET = 10.15;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SWIFT_COMPILATION_MODE = wholemodule;
Expand All @@ -524,10 +554,12 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"deepa/Preview Content\"";
DEVELOPMENT_TEAM = X8ZFLUE894;
DEVELOPMENT_TEAM = Z7X6647APW;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = deepa/Info.plist;
INFOPLIST_KEY_NSLocalNetworkUsageDescription = "Atlantis would use Bonjour Service to discover Proxyman app from your local network.";
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
"INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
Expand All @@ -543,7 +575,7 @@
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 12.3;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.niveumlabs.deepa;
PRODUCT_BUNDLE_IDENTIFIER = com.donchia.deepa;
Copy link
Contributor

Choose a reason for hiding this comment

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

woops, don't commit this lol

PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
Expand All @@ -562,10 +594,12 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"deepa/Preview Content\"";
DEVELOPMENT_TEAM = X8ZFLUE894;
DEVELOPMENT_TEAM = Z7X6647APW;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_FILE = deepa/Info.plist;
INFOPLIST_KEY_NSLocalNetworkUsageDescription = "Atlantis would use Bonjour Service to discover Proxyman app from your local network.";
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
"INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
Expand All @@ -581,7 +615,7 @@
"LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 12.3;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.niveumlabs.deepa;
PRODUCT_BUNDLE_IDENTIFIER = com.donchia.deepa;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx";
Expand Down Expand Up @@ -731,6 +765,14 @@
minimumVersion = 0.53.0;
};
};
5A936E7028D6234A00C6065B /* XCRemoteSwiftPackageReference "atlantis" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/ProxymanApp/atlantis";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.18.2;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
Expand All @@ -744,6 +786,11 @@
package = 5A936E5728D5A8B200C6065B /* XCRemoteSwiftPackageReference "apollo-ios" */;
productName = ApolloWebSocket;
};
5A936E7128D6234A00C6065B /* Atlantis */ = {
isa = XCSwiftPackageProductDependency;
package = 5A936E7028D6234A00C6065B /* XCRemoteSwiftPackageReference "atlantis" */;
productName = Atlantis;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 5A936E1228D377C200C6065B /* Project object */;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions deepa/Assets.xcassets/AccentColor.colorset/Contents.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
{
"colors" : [
{
"color" : {
"platform" : "universal",
"reference" : "systemOrangeColor"
},
"idiom" : "universal"
}
],
Expand Down
2 changes: 1 addition & 1 deletion deepa/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ struct ContentView: View {
}
WorkshopView()
.tabItem {
Label("Workshop", systemImage: "laptopcomputer")
Label("Workshop", systemImage: "swift")
}
NewsView()
.tabItem {
Expand Down
49 changes: 26 additions & 23 deletions deepa/Helpers/NetworkManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,29 +13,32 @@ class NetworkManager {
static let shared = NetworkManager()
let httpsEndpoint = "https://iosconfsg.herokuapp.com/v1/graphql"
let wsEndpoint = "ws://iosconfsg.herokuapp.com/v1/graphql"
var apolloClient: ApolloClient?

private init() {
createApolloClient()
}
/// A web socket transport to use for subscriptions
private lazy var webSocketTransport: WebSocketTransport = {
let url = URL(string: wsEndpoint)!
let webSocketClient = WebSocket(url: url, protocol: .graphql_transport_ws)
return WebSocketTransport(websocket: webSocketClient)
}()

func createApolloClient() {
self.apolloClient = {
guard let wsEndpointUrl = URL(string: wsEndpoint) else { return nil }
guard let httpsEndpointUrl = URL(string: httpsEndpoint) else { return nil}

let request = URLRequest(url: wsEndpointUrl)
let websocket = WebSocket(request: request, protocol: .graphql_transport_ws)
let websocketTransport = WebSocketTransport(websocket: websocket)

let store = ApolloStore(cache: InMemoryNormalizedCache())

let provider = DefaultInterceptorProvider(store: store)
let httpNetworkTransport = RequestChainNetworkTransport(interceptorProvider: provider, endpointURL: httpsEndpointUrl)
let splitNetworkTransport = SplitNetworkTransport(uploadingNetworkTransport: httpNetworkTransport, webSocketNetworkTransport: websocketTransport)

return ApolloClient(networkTransport: splitNetworkTransport, store: store)

}()
}
/// An HTTP transport to use for queries and mutations

private lazy var normalTransport: RequestChainNetworkTransport = {
let url = URL(string: httpsEndpoint)!
return RequestChainNetworkTransport(interceptorProvider: DefaultInterceptorProvider(store: self.store), endpointURL: url)
}()


/// A split network transport to allow the use of both of the above
/// transports through a single `NetworkTransport` instance.
private lazy var splitNetworkTransport = SplitNetworkTransport(
uploadingNetworkTransport: self.normalTransport,
webSocketNetworkTransport: self.webSocketTransport
)

/// Create a client using the `SplitNetworkTransport`.
private(set) lazy var client = ApolloClient(networkTransport: self.splitNetworkTransport, store: self.store)

/// A common store to use for `normalTransport` and `client`.
private lazy var store = ApolloStore()
}
12 changes: 12 additions & 0 deletions deepa/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?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>NSLocalNetworkUsageDescription</key>
<string>Atlantis would use Bonjour Service to discover Proxyman app from your local network.</string>
<key>NSBonjourServices</key>
<array>
<string>_Proxyman._tcp</string>
</array>
</dict>
</plist>
51 changes: 45 additions & 6 deletions deepa/Info/InfoView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,54 @@
//

import SwiftUI
import SafariServices

struct InfoView: View {
var body: some View {
Text("Info")
struct AboutMenu: Identifiable {
var id = UUID()
var title: String
var link: String
}

struct SFSafariViewWrapper: UIViewControllerRepresentable {
let url: URL

func makeUIViewController(context: UIViewControllerRepresentableContext<Self>) -> SFSafariViewController {
return SFSafariViewController(url: url)
}

func updateUIViewController(_ uiViewController: SFSafariViewController, context: UIViewControllerRepresentableContext<SFSafariViewWrapper>) {
return
}
}

struct InfoView_Previews: PreviewProvider {
static var previews: some View {
InfoView()
struct InfoView: View {
@State var menuList: Array<AboutMenu> = [
AboutMenu(title: "Code of Conduct", link: "https://iosconf.sg/coc"),
AboutMenu(title: "Sponsors", link: "https://iosconf.sg/#sponsors"),
AboutMenu(title: "Software", link: "https://iosconf.sg/software"),
AboutMenu(title: "FAQ", link: "https://iosconf.sg/faq")]
@State private var showSafari: Bool = false

var body: some View {
NavigationView {
List {
Section {
ForEach(menuList) { menu in
Button(action: {
showSafari.toggle()
}) {
Text("\(menu.title)")
}.fullScreenCover(isPresented: $showSafari, content: {
SFSafariViewWrapper(url: URL(string: "\(menu.link)")!).ignoresSafeArea(.all)
})
}
}
Section {
Link("Open iOSConfSG Slack", destination: URL(string: "www.slack.com")!)
}
}
.listStyle(.grouped)
.navigationTitle("About")
}
}
}
20 changes: 20 additions & 0 deletions deepa/Models/Speaker.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//
// Speaker.swift
// deepa
//
// Created by Vina Melody on 17/9/22.
//

import Foundation

struct Speaker: Identifiable {
var id: Int
var name: String
var shortBio: String?
var twitter: String?
var linkedIn: String?
var company: String?
var companyUrl: String?
var imageUrl: String?
var imageFilename: String?
}
Loading