Invite screen and liberated invite code and tests
This commit is contained in:
parent
c870646780
commit
1e336b256b
|
@ -53,6 +53,10 @@
|
|||
0DB5331024A623AF0090D722 /* sapling-output.params in Resources */ = {isa = PBXBuildFile; fileRef = 0DB5330E24A623AF0090D722 /* sapling-output.params */; };
|
||||
0DB5331224A6413D0090D722 /* LazyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DB5331124A6413D0090D722 /* LazyView.swift */; };
|
||||
0DB5331424A6B8B60090D722 /* memo.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DB5331324A6B8B60090D722 /* memo.pb.swift */; };
|
||||
0DB9EF5624AFA94300FE89E6 /* LiberatedInviteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DB9EF5524AFA94300FE89E6 /* LiberatedInviteTests.swift */; };
|
||||
0DB9EF5824AFAA6100FE89E6 /* InviteHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DB9EF5724AFAA6100FE89E6 /* InviteHandler.swift */; };
|
||||
0DB9EF5A24AFF03400FE89E6 /* InvitePeople.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DB9EF5924AFF03400FE89E6 /* InvitePeople.swift */; };
|
||||
0DB9EF5C24B001A000FE89E6 /* ShareView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DB9EF5B24B001A000FE89E6 /* ShareView.swift */; };
|
||||
0DC1B47B24AAA44B00AEF3D0 /* ZircleService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DC1B47A24AAA44B00AEF3D0 /* ZircleService.swift */; };
|
||||
0DC4B44A24ACB62400B3CBA2 /* darkside.grpc.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DC4B43D24ACB62400B3CBA2 /* darkside.grpc.swift */; };
|
||||
0DC4B44B24ACB62400B3CBA2 /* darkside.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DC4B43E24ACB62400B3CBA2 /* darkside.pb.swift */; };
|
||||
|
@ -145,6 +149,10 @@
|
|||
0DB5330E24A623AF0090D722 /* sapling-output.params */ = {isa = PBXFileReference; lastKnownFileType = file; path = "sapling-output.params"; sourceTree = "<group>"; };
|
||||
0DB5331124A6413D0090D722 /* LazyView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LazyView.swift; sourceTree = "<group>"; };
|
||||
0DB5331324A6B8B60090D722 /* memo.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = memo.pb.swift; sourceTree = "<group>"; };
|
||||
0DB9EF5524AFA94300FE89E6 /* LiberatedInviteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = LiberatedInviteTests.swift; path = ZirclesTests/LiberatedInviteTests.swift; sourceTree = SOURCE_ROOT; };
|
||||
0DB9EF5724AFAA6100FE89E6 /* InviteHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InviteHandler.swift; sourceTree = "<group>"; };
|
||||
0DB9EF5924AFF03400FE89E6 /* InvitePeople.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InvitePeople.swift; sourceTree = "<group>"; };
|
||||
0DB9EF5B24B001A000FE89E6 /* ShareView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareView.swift; sourceTree = "<group>"; };
|
||||
0DC1B47A24AAA44B00AEF3D0 /* ZircleService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZircleService.swift; sourceTree = "<group>"; };
|
||||
0DC4B43D24ACB62400B3CBA2 /* darkside.grpc.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = darkside.grpc.swift; sourceTree = "<group>"; };
|
||||
0DC4B43E24ACB62400B3CBA2 /* darkside.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = darkside.pb.swift; sourceTree = "<group>"; };
|
||||
|
@ -230,6 +238,7 @@
|
|||
0D64CEC024A3F2580080AA4F /* FirstScreen.swift */,
|
||||
0D64CEC224A4137D0080AA4F /* ZircleData.swift */,
|
||||
0D3FB6FD24A4CD4E0034A52A /* MockEnvironment.swift */,
|
||||
0DB9EF5B24B001A000FE89E6 /* ShareView.swift */,
|
||||
);
|
||||
path = Utils;
|
||||
sourceTree = "<group>";
|
||||
|
@ -292,6 +301,7 @@
|
|||
0D1366C124991A6200F0EB54 /* ZirclesTests */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0DB9EF5524AFA94300FE89E6 /* LiberatedInviteTests.swift */,
|
||||
0DC4B43C24ACB62400B3CBA2 /* proto */,
|
||||
0DC4B44024ACB62400B3CBA2 /* utils */,
|
||||
0D1366C224991A6200F0EB54 /* ZirclesTests.swift */,
|
||||
|
@ -319,6 +329,7 @@
|
|||
0DEE59A924A2B90F00447C15 /* CreateNewZircleDescription.swift */,
|
||||
0D64CEC424A41AF30080AA4F /* AppDetails.swift */,
|
||||
0DD7278824A5532300C36D27 /* AllZirclesView.swift */,
|
||||
0DB9EF5924AFF03400FE89E6 /* InvitePeople.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
|
@ -361,6 +372,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
0DC1B47A24AAA44B00AEF3D0 /* ZircleService.swift */,
|
||||
0DB9EF5724AFAA6100FE89E6 /* InviteHandler.swift */,
|
||||
);
|
||||
path = ZircleService;
|
||||
sourceTree = "<group>";
|
||||
|
@ -663,6 +675,7 @@
|
|||
0D11D3D4249D05D800223146 /* Wedge.swift in Sources */,
|
||||
0D1366AE24991A6000F0EB54 /* SceneDelegate.swift in Sources */,
|
||||
0D11D3D0249C3AE400223146 /* Card.swift in Sources */,
|
||||
0DB9EF5C24B001A000FE89E6 /* ShareView.swift in Sources */,
|
||||
0D64CEB724A3CDA90080AA4F /* QRCodeGenerator.swift in Sources */,
|
||||
0D64CEBF24A3D3A30080AA4F /* CombineSynchronizer.swift in Sources */,
|
||||
0DD7278B24A564AF00C36D27 /* ZircleListCard.swift in Sources */,
|
||||
|
@ -677,10 +690,12 @@
|
|||
0D64CEBA24A3CDA90080AA4F /* zECC+SwiftUI.swift in Sources */,
|
||||
0D11D3D2249CE6C800223146 /* GlowEffect.swift in Sources */,
|
||||
0D64CEB524A3CDA90080AA4F /* String+Zcash.swift in Sources */,
|
||||
0DB9EF5A24AFF03400FE89E6 /* InvitePeople.swift in Sources */,
|
||||
0DB5331224A6413D0090D722 /* LazyView.swift in Sources */,
|
||||
0D11D3DB249D5F1600223146 /* NeumorphicProgressBar.swift in Sources */,
|
||||
0D64CEBD24A3CDA90080AA4F /* SimpleLogger.swift in Sources */,
|
||||
0D64CEBC24A3CDA90080AA4F /* BalanceUtils.swift in Sources */,
|
||||
0DB9EF5824AFAA6100FE89E6 /* InviteHandler.swift in Sources */,
|
||||
0D5142C824A16F9600F9AE2E /* CreateNewTypeOfZircle.swift in Sources */,
|
||||
0DB5331424A6B8B60090D722 /* memo.pb.swift in Sources */,
|
||||
0D64CEBB24A3CDA90080AA4F /* CameraAccessHelper.swift in Sources */,
|
||||
|
@ -706,6 +721,7 @@
|
|||
0DC4B44B24ACB62400B3CBA2 /* darkside.pb.swift in Sources */,
|
||||
0DC4B45324ACB62400B3CBA2 /* Stubs.swift in Sources */,
|
||||
0DC4B45124ACB62400B3CBA2 /* TestDbBuilder.swift in Sources */,
|
||||
0DB9EF5624AFA94300FE89E6 /* LiberatedInviteTests.swift in Sources */,
|
||||
0DC4B45224ACB62400B3CBA2 /* FakeChainBuilder.swift in Sources */,
|
||||
0DC4B44E24ACB62400B3CBA2 /* SampleLogger.swift in Sources */,
|
||||
0DC4B45724ACF8EE00B3CBA2 /* TestCoordinator.swift in Sources */,
|
||||
|
|
|
@ -128,7 +128,7 @@ extension SeedManager {
|
|||
guard keychain.get(spendingKeyKey(key)) == nil else {
|
||||
throw SeedManagerError.alreadyImported
|
||||
}
|
||||
keychain.set(String(phrase), forKey: spendingKeyKey(key))
|
||||
keychain.set(String(spendingKey), forKey: spendingKeyKey(key))
|
||||
}
|
||||
|
||||
func getZircleKeys(_ key: String) throws -> (height: BlockHeight, phrase: String, spendingKey: String)? {
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// ShareView.swift
|
||||
// Zircles
|
||||
//
|
||||
// Created by Francisco Gindre on 7/3/20.
|
||||
// Copyright © 2020 Electric Coin Company. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
struct ShareSheet: UIViewControllerRepresentable {
|
||||
typealias Callback = (_ activityType: UIActivity.ActivityType?, _ completed: Bool, _ returnedItems: [Any]?, _ error: Error?) -> Void
|
||||
|
||||
let activityItems: [Any]
|
||||
let applicationActivities: [UIActivity]? = nil
|
||||
let excludedActivityTypes: [UIActivity.ActivityType]? = nil
|
||||
let callback: Callback? = nil
|
||||
|
||||
func makeUIViewController(context: Context) -> UIActivityViewController {
|
||||
let controller = UIActivityViewController(
|
||||
activityItems: activityItems,
|
||||
applicationActivities: applicationActivities)
|
||||
controller.excludedActivityTypes = excludedActivityTypes
|
||||
controller.completionWithItemsHandler = callback
|
||||
return controller
|
||||
}
|
||||
|
||||
func updateUIViewController(_ uiViewController: UIActivityViewController, context: Context) {
|
||||
// nothing to do here
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
//
|
||||
// InvitePeople.swift
|
||||
// Zircles
|
||||
//
|
||||
// Created by Francisco Gindre on 7/3/20.
|
||||
// Copyright © 2020 Electric Coin Company. All rights reserved.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct InvitePeople: View {
|
||||
let liberatedZircle: String
|
||||
@State var isSharing = false
|
||||
var body: some View {
|
||||
ZStack {
|
||||
VStack(spacing: 0) {
|
||||
Image("Invite").edgesIgnoringSafeArea(.all)
|
||||
.frame(alignment: .top)
|
||||
Spacer()
|
||||
}
|
||||
VStack(spacing:20) {
|
||||
Spacer()
|
||||
HStack() {
|
||||
Text("""
|
||||
Invite
|
||||
Some Peeps
|
||||
""")
|
||||
.font(.largeTitle)
|
||||
.fontWeight(.bold)
|
||||
.foregroundColor(.white)
|
||||
.multilineTextAlignment(.leading)
|
||||
Spacer()
|
||||
}
|
||||
.padding(.horizontal, 30)
|
||||
ZStack {
|
||||
Color.background
|
||||
VStack(spacing: 20) {
|
||||
Text("This is your Sharing Link")
|
||||
.font(.title)
|
||||
|
||||
Text(liberatedZircle)
|
||||
.font(.body)
|
||||
.lineLimit(3)
|
||||
.truncationMode(.middle)
|
||||
.foregroundColor(.textLightGray)
|
||||
Button(action:{}){
|
||||
Text("Copy To clipboard")
|
||||
.font(.system(size: 20, weight: .bold, design: .default))
|
||||
.shadow(color:Color(red: 0.2, green: 0.2, blue: 0.2).opacity(0.2), radius: 1, x: 0, y: 2)
|
||||
.foregroundColor(Color.textDarkGray)
|
||||
.modifier(ZcashButtonBackground(buttonShape: .roundedCorners(fillStyle: .solid(color: Color.buttonGray))))
|
||||
|
||||
.shadow(color: Color(red: 0.2, green: 0.2, blue: 0.2).opacity(0.5), radius: 25, x: 10, y: 10)
|
||||
.frame(height: 50)
|
||||
}
|
||||
Button(action: {
|
||||
self.isSharing = true
|
||||
}, label: {
|
||||
Text("Invite People")
|
||||
.font(.system(size: 20, weight: .bold, design: .default))
|
||||
.shadow(color:Color(red: 0.2, green: 0.2, blue: 0.2).opacity(0.2), radius: 1, x: 0, y: 2)
|
||||
.foregroundColor(Color.background)
|
||||
.modifier(ZcashButtonBackground(buttonShape: .roundedCorners(fillStyle: .solid(color: Color.buttonBlue))))
|
||||
|
||||
.shadow(color: Color(red: 0.2, green: 0.2, blue: 0.2).opacity(0.5), radius: 25, x: 10, y: 10)
|
||||
.frame(height: 50)
|
||||
})
|
||||
}
|
||||
.padding(.all, 30)
|
||||
}.cornerRadius(25, corners: [.topLeft,.topRight])
|
||||
.frame(height: 300,
|
||||
alignment: .bottom)
|
||||
}.background(Color.clear)
|
||||
}
|
||||
.navigationBarTitle("", displayMode: .inline)
|
||||
.sheet(isPresented: $isSharing) {
|
||||
ShareSheet(activityItems: [liberatedZircle])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct RoundedCorner: Shape {
|
||||
|
||||
var radius: CGFloat = .infinity
|
||||
var corners: UIRectCorner = .allCorners
|
||||
|
||||
func path(in rect: CGRect) -> Path {
|
||||
let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
|
||||
return Path(path.cgPath)
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {
|
||||
clipShape( RoundedCorner(radius: radius, corners: corners) )
|
||||
}
|
||||
}
|
||||
|
||||
struct InvitePeople_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
InvitePeople(liberatedZircle: LiberatedInviteHandler.inviteWith(name: "Hackathon Drinks", viewingkey: "zxviews1qvhluf0pqqqqpq8ywsuq89wulufzghltkt76vz33rrhpaekeakr68at2lglxwfuxkth58vw8cp9s8z0qguqzxc0wfaz6f4mp7vfs47hex6n38tczds7uakalf3a25qwth56v8tz95p4qfyjquk7thwzr3uq6hwgwu4emxm3wrf3yspgatcvup83pl96jrvaymznxa5vdlh6dfgfuzja3egv96hg5eyelrlgkf29su9hucds8zjt2lnsqlcaajq7klkjxc40v80d6sfqkvwjet", height: 663190).absoluteString)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
//
|
||||
// InviteHandler.swift
|
||||
// Zircles
|
||||
//
|
||||
// Created by Francisco Gindre on 7/3/20.
|
||||
// Copyright © 2020 Electric Coin Company. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
/**
|
||||
Liberated Invite
|
||||
3 parameters
|
||||
https://invite.zircles.co?vk=xxxxxxxxxx&height=xxxxxxxxx&name=xxxxxxx
|
||||
*/
|
||||
|
||||
struct LiberatedInvite {
|
||||
let name: String
|
||||
let viewingKey: String
|
||||
let height: Int
|
||||
}
|
||||
|
||||
class LiberatedInviteHandler {
|
||||
|
||||
enum InviteComponents: String {
|
||||
case scheme = "https"
|
||||
case host = "invite.zircles.co"
|
||||
case viewingKey = "vk"
|
||||
case height
|
||||
case name
|
||||
}
|
||||
|
||||
static func inviteWith(name: String,
|
||||
viewingkey: String,
|
||||
height: Int) -> URL {
|
||||
|
||||
let nameItem = URLQueryItem(name: InviteComponents.name.rawValue, value: name)
|
||||
let viewingkeyItem = URLQueryItem(name: InviteComponents.viewingKey.rawValue, value: viewingkey)
|
||||
let heightItem = URLQueryItem(name: InviteComponents.height.rawValue, value: String(height))
|
||||
|
||||
var components = URLComponents()
|
||||
components.scheme = InviteComponents.scheme.rawValue
|
||||
components.host = InviteComponents.host.rawValue
|
||||
components.queryItems = [ nameItem, viewingkeyItem, heightItem]
|
||||
|
||||
return components.url!
|
||||
}
|
||||
|
||||
static func parseInvite(_ url: URL) -> LiberatedInvite? {
|
||||
guard url.host == InviteComponents.host.rawValue else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let parsedScheme = url.scheme,
|
||||
parsedScheme == InviteComponents.scheme.rawValue else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let vk = components.queryItems?.first(where: { $0.name == InviteComponents.viewingKey.rawValue})?.value else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let name = components.queryItems?.first(where: {$0.name == InviteComponents.name.rawValue})?.value else {
|
||||
return nil
|
||||
}
|
||||
|
||||
guard let heightParam = components.queryItems?.first(where: { $0.name == InviteComponents.height.rawValue })?.value,
|
||||
let height = Int(heightParam) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
return LiberatedInvite(name: name,
|
||||
viewingKey: vk,
|
||||
height: height)
|
||||
}
|
||||
}
|
|
@ -72,6 +72,7 @@ struct ConcreteZircle: ZircleEntity {
|
|||
import MnemonicSwift
|
||||
|
||||
extension CombineSynchronizer: ZircleService {
|
||||
|
||||
func closeZircle(name: String) throws {
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// LiberatedInviteTests.swift
|
||||
// ZirclesTests
|
||||
//
|
||||
// Created by Francisco Gindre on 7/3/20.
|
||||
// Copyright © 2020 Electric Coin Company. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Zircles
|
||||
class LiberatedInviteTests: XCTestCase {
|
||||
|
||||
let extendedViewingKey: String = "zxviews1qvhluf0pqqqqpq8ywsuq89wulufzghltkt76vz33rrhpaekeakr68at2lglxwfuxkth58vw8cp9s8z0qguqzxc0wfaz6f4mp7vfs47hex6n38tczds7uakalf3a25qwth56v8tz95p4qfyjquk7thwzr3uq6hwgwu4emxm3wrf3yspgatcvup83pl96jrvaymznxa5vdlh6dfgfuzja3egv96hg5eyelrlgkf29su9hucds8zjt2lnsqlcaajq7klkjxc40v80d6sfqkvwjet"
|
||||
|
||||
let zircleName = "Hackathon Drinks"
|
||||
let height: Int = 663190
|
||||
|
||||
func expectedUrlString() -> String {
|
||||
LiberatedInviteHandler.InviteComponents.scheme.rawValue +
|
||||
"://" +
|
||||
LiberatedInviteHandler.InviteComponents.host.rawValue + "?name=\(zircleName.replacingOccurrences(of: " ", with: "%20"))&vk=\(extendedViewingKey)&height=\(height)"
|
||||
}
|
||||
|
||||
func testHappyPath() throws {
|
||||
guard let parsedInvite = LiberatedInviteHandler.parseInvite(URL(string: expectedUrlString())!) else {
|
||||
XCTFail("parsed invite nil")
|
||||
return
|
||||
}
|
||||
XCTAssertEqual(parsedInvite.name, zircleName)
|
||||
XCTAssertEqual(parsedInvite.height, height)
|
||||
XCTAssertEqual(parsedInvite.viewingKey, extendedViewingKey)
|
||||
}
|
||||
|
||||
func testLiberatedPaymentGeneration() {
|
||||
let invite = LiberatedInviteHandler.inviteWith(name: zircleName, viewingkey: extendedViewingKey, height: height)
|
||||
|
||||
XCTAssertEqual(invite, URL(string: expectedUrlString())!)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue