forked from mirrors/linphone-iphone
Add QRCode Scanner View
This commit is contained in:
parent
55d7bf8de7
commit
b967b67598
16 changed files with 420 additions and 57 deletions
|
|
@ -18,6 +18,10 @@
|
|||
D719ABC92ABC6FD700B41C10 /* CoreContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = D719ABC82ABC6FD700B41C10 /* CoreContext.swift */; };
|
||||
D719ABCC2ABC769C00B41C10 /* AssistantView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D719ABCB2ABC769C00B41C10 /* AssistantView.swift */; };
|
||||
D719ABCF2ABC779A00B41C10 /* AccountLoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D719ABCE2ABC779A00B41C10 /* AccountLoginViewModel.swift */; };
|
||||
D72343302ACEFEF8009AA24E /* QrCodeScannerFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D723432F2ACEFEF8009AA24E /* QrCodeScannerFragment.swift */; };
|
||||
D72343322ACEFF58009AA24E /* QRScannerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72343312ACEFF58009AA24E /* QRScannerController.swift */; };
|
||||
D72343342ACEFFC3009AA24E /* QRScanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72343332ACEFFC3009AA24E /* QRScanner.swift */; };
|
||||
D72343362AD037AF009AA24E /* ToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D72343352AD037AF009AA24E /* ToastView.swift */; };
|
||||
D748BF2C2ACD82D2004844EB /* ThirdPartySipAccountLoginFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D748BF2B2ACD82D2004844EB /* ThirdPartySipAccountLoginFragment.swift */; };
|
||||
D748BF2E2ACD82E7004844EB /* ThirdPartySipAccountWarningFragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D748BF2D2ACD82E7004844EB /* ThirdPartySipAccountWarningFragment.swift */; };
|
||||
D74C9CF82ACACECE0021626A /* WelcomePage1Fragment.swift in Sources */ = {isa = PBXBuildFile; fileRef = D74C9CF72ACACECE0021626A /* WelcomePage1Fragment.swift */; };
|
||||
|
|
@ -55,6 +59,10 @@
|
|||
D719ABC82ABC6FD700B41C10 /* CoreContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreContext.swift; sourceTree = "<group>"; };
|
||||
D719ABCB2ABC769C00B41C10 /* AssistantView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AssistantView.swift; sourceTree = "<group>"; };
|
||||
D719ABCE2ABC779A00B41C10 /* AccountLoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountLoginViewModel.swift; sourceTree = "<group>"; };
|
||||
D723432F2ACEFEF8009AA24E /* QrCodeScannerFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QrCodeScannerFragment.swift; sourceTree = "<group>"; };
|
||||
D72343312ACEFF58009AA24E /* QRScannerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRScannerController.swift; sourceTree = "<group>"; };
|
||||
D72343332ACEFFC3009AA24E /* QRScanner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRScanner.swift; sourceTree = "<group>"; };
|
||||
D72343352AD037AF009AA24E /* ToastView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToastView.swift; sourceTree = "<group>"; };
|
||||
D748BF2B2ACD82D2004844EB /* ThirdPartySipAccountLoginFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThirdPartySipAccountLoginFragment.swift; sourceTree = "<group>"; };
|
||||
D748BF2D2ACD82E7004844EB /* ThirdPartySipAccountWarningFragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThirdPartySipAccountWarningFragment.swift; sourceTree = "<group>"; };
|
||||
D74C9CF72ACACECE0021626A /* WelcomePage1Fragment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomePage1Fragment.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -114,6 +122,7 @@
|
|||
D717071D2AC5922E0037746F /* ColorExtension.swift */,
|
||||
D717071F2AC5989C0037746F /* TextExtension.swift */,
|
||||
D74C9D002ACB098C0021626A /* PermissionManager.swift */,
|
||||
D72343312ACEFF58009AA24E /* QRScannerController.swift */,
|
||||
);
|
||||
path = Utils;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -206,6 +215,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
D719ABCE2ABC779A00B41C10 /* AccountLoginViewModel.swift */,
|
||||
D72343332ACEFFC3009AA24E /* QRScanner.swift */,
|
||||
);
|
||||
path = Viewmodel;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -224,6 +234,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
D74C9CFE2ACAEC5E0021626A /* PopupView.swift */,
|
||||
D72343352AD037AF009AA24E /* ToastView.swift */,
|
||||
);
|
||||
path = Fragments;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -281,6 +292,7 @@
|
|||
D7DA67632ACCB31700E95002 /* ProfileModeFragment.swift */,
|
||||
D748BF2B2ACD82D2004844EB /* ThirdPartySipAccountLoginFragment.swift */,
|
||||
D748BF2D2ACD82E7004844EB /* ThirdPartySipAccountWarningFragment.swift */,
|
||||
D723432F2ACEFEF8009AA24E /* QrCodeScannerFragment.swift */,
|
||||
);
|
||||
path = Fragments;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -420,6 +432,10 @@
|
|||
D748BF2E2ACD82E7004844EB /* ThirdPartySipAccountWarningFragment.swift in Sources */,
|
||||
D748BF2C2ACD82D2004844EB /* ThirdPartySipAccountLoginFragment.swift in Sources */,
|
||||
D74C9CF82ACACECE0021626A /* WelcomePage1Fragment.swift in Sources */,
|
||||
D72343362AD037AF009AA24E /* ToastView.swift in Sources */,
|
||||
D72343322ACEFF58009AA24E /* QRScannerController.swift in Sources */,
|
||||
D72343342ACEFFC3009AA24E /* QRScanner.swift in Sources */,
|
||||
D72343302ACEFEF8009AA24E /* QrCodeScannerFragment.swift in Sources */,
|
||||
D717071E2AC5922E0037746F /* ColorExtension.swift in Sources */,
|
||||
D7DA67642ACCB31700E95002 /* ProfileModeFragment.swift in Sources */,
|
||||
D74C9CFC2ACACF370021626A /* WelcomePage3Fragment.swift in Sources */,
|
||||
|
|
@ -563,6 +579,7 @@
|
|||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = Linphone/Info.plist;
|
||||
INFOPLIST_KEY_NSCameraUsageDescription = "Share photos with your friends and customize avatars";
|
||||
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "";
|
||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
|
||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
|
||||
|
|
@ -606,6 +623,7 @@
|
|||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = Linphone/Info.plist;
|
||||
INFOPLIST_KEY_NSCameraUsageDescription = "Share photos with your friends and customize avatars";
|
||||
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "";
|
||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
|
||||
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
|
||||
|
|
|
|||
21
Linphone/Assets.xcassets/danger.imageset/Contents.json
vendored
Normal file
21
Linphone/Assets.xcassets/danger.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "danger.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
3
Linphone/Assets.xcassets/danger.imageset/danger.svg
vendored
Normal file
3
Linphone/Assets.xcassets/danger.imageset/danger.svg
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="25" height="24" viewBox="0 0 25 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.5 2C10.5222 2 8.58879 2.58649 6.9443 3.6853C5.29981 4.78412 4.01809 6.3459 3.26121 8.17316C2.50433 10.0004 2.3063 12.0111 2.69215 13.9509C3.078 15.8907 4.03041 17.6725 5.42894 19.0711C6.82746 20.4696 8.60929 21.422 10.5491 21.8078C12.4889 22.1937 14.4996 21.9957 16.3268 21.2388C18.1541 20.4819 19.7159 19.2002 20.8147 17.5557C21.9135 15.9112 22.5 13.9778 22.5 12C22.4972 9.34869 21.4427 6.80678 19.568 4.93202C17.6932 3.05727 15.1513 2.0028 12.5 2ZM11.7308 7.38461C11.7308 7.1806 11.8118 6.98494 11.9561 6.84069C12.1003 6.69643 12.296 6.61538 12.5 6.61538C12.704 6.61538 12.8997 6.69643 13.0439 6.84069C13.1882 6.98494 13.2692 7.1806 13.2692 7.38461V12.7692C13.2692 12.9732 13.1882 13.1689 13.0439 13.3132C12.8997 13.4574 12.704 13.5385 12.5 13.5385C12.296 13.5385 12.1003 13.4574 11.9561 13.3132C11.8118 13.1689 11.7308 12.9732 11.7308 12.7692V7.38461ZM12.5 17.3846C12.2718 17.3846 12.0487 17.3169 11.859 17.1902C11.6692 17.0634 11.5213 16.8832 11.434 16.6723C11.3467 16.4615 11.3238 16.2295 11.3683 16.0057C11.4128 15.7818 11.5227 15.5762 11.6841 15.4149C11.8455 15.2535 12.0511 15.1436 12.2749 15.0991C12.4987 15.0546 12.7307 15.0774 12.9416 15.1648C13.1524 15.2521 13.3326 15.4 13.4594 15.5897C13.5862 15.7795 13.6538 16.0026 13.6538 16.2308C13.6538 16.5368 13.5323 16.8303 13.3159 17.0467C13.0995 17.263 12.806 17.3846 12.5 17.3846Z" fill="#DD5F5F"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
21
Linphone/Assets.xcassets/success.imageset/Contents.json
vendored
Normal file
21
Linphone/Assets.xcassets/success.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "success.svg",
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
3
Linphone/Assets.xcassets/success.imageset/success.svg
vendored
Normal file
3
Linphone/Assets.xcassets/success.imageset/success.svg
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 2C10.0222 2 8.08879 2.58649 6.4443 3.6853C4.79981 4.78412 3.51809 6.3459 2.76121 8.17316C2.00433 10.0004 1.8063 12.0111 2.19215 13.9509C2.578 15.8907 3.53041 17.6725 4.92894 19.0711C6.32746 20.4696 8.10929 21.422 10.0491 21.8078C11.9889 22.1937 13.9996 21.9957 15.8268 21.2388C17.6541 20.4819 19.2159 19.2002 20.3147 17.5557C21.4135 15.9112 22 13.9778 22 12C21.9972 9.34869 20.9427 6.80678 19.068 4.93202C17.1932 3.05727 14.6513 2.0028 12 2ZM12 20.4615C10.3265 20.4615 8.69052 19.9653 7.29902 19.0355C5.90753 18.1057 4.823 16.7842 4.18256 15.2381C3.54213 13.6919 3.37456 11.9906 3.70105 10.3492C4.02754 8.70786 4.83343 7.20016 6.01679 6.01679C7.20016 4.83342 8.70786 4.02754 10.3492 3.70105C11.9906 3.37456 13.6919 3.54212 15.2381 4.18256C16.7842 4.82299 18.1057 5.90753 19.0355 7.29902C19.9653 8.69051 20.4615 10.3265 20.4615 12C20.459 14.2434 19.5667 16.3941 17.9804 17.9804C16.3941 19.5667 14.2434 20.459 12 20.4615ZM7.38462 10.0769C7.38462 9.84871 7.45229 9.62563 7.57908 9.43588C7.70586 9.24613 7.88607 9.09824 8.09691 9.01091C8.30774 8.92357 8.53974 8.90072 8.76357 8.94525C8.98739 8.98977 9.19299 9.09966 9.35436 9.26103C9.51573 9.4224 9.62562 9.62799 9.67014 9.85182C9.71466 10.0756 9.69181 10.3076 9.60448 10.5185C9.51715 10.7293 9.36926 10.9095 9.17951 11.0363C8.98976 11.1631 8.76667 11.2308 8.53846 11.2308C8.23245 11.2308 7.93896 11.1092 7.72257 10.8928C7.50618 10.6764 7.38462 10.3829 7.38462 10.0769ZM16.6154 10.0769C16.6154 10.3051 16.5477 10.5282 16.4209 10.718C16.2941 10.9077 16.1139 11.0556 15.9031 11.1429C15.6923 11.2303 15.4603 11.2531 15.2364 11.2086C15.0126 11.1641 14.807 11.0542 14.6456 10.8928C14.4843 10.7314 14.3744 10.5259 14.3299 10.302C14.2853 10.0782 14.3082 9.8462 14.3955 9.63536C14.4829 9.42453 14.6307 9.24432 14.8205 9.11753C15.0102 8.99075 15.2333 8.92308 15.4615 8.92308C15.7676 8.92308 16.061 9.04464 16.2774 9.26103C16.4938 9.47742 16.6154 9.7709 16.6154 10.0769ZM16.5125 14.6923C15.5231 16.4029 13.8779 17.3846 12 17.3846C10.1221 17.3846 8.47789 16.4038 7.48846 14.6923C7.43281 14.6048 7.39544 14.5068 7.3786 14.4045C7.36176 14.3021 7.36581 14.1974 7.39049 14.0966C7.41517 13.9959 7.45998 13.9011 7.52222 13.8181C7.58447 13.7351 7.66285 13.6656 7.75267 13.6137C7.84249 13.5617 7.94189 13.5285 8.04487 13.516C8.14786 13.5035 8.25232 13.512 8.35195 13.5409C8.45159 13.5698 8.54435 13.6185 8.62466 13.6842C8.70496 13.7499 8.77114 13.8311 8.81923 13.9231C9.5375 15.1644 10.6663 15.8462 12 15.8462C13.3337 15.8462 14.4625 15.1635 15.1798 13.9231C15.2818 13.7463 15.4498 13.6174 15.6469 13.5645C15.844 13.5117 16.054 13.5393 16.2308 13.6413C16.4075 13.7434 16.5365 13.9114 16.5893 14.1085C16.6421 14.3056 16.6145 14.5156 16.5125 14.6923Z" fill="#4FAE80"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
|
|
@ -1,21 +1,21 @@
|
|||
/*
|
||||
* Copyright (c) 2010-2023 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of Linphone
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
* Copyright (c) 2010-2023 Belledonne Communications SARL.
|
||||
*
|
||||
* This file is part of Linphone
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import linphonesw
|
||||
|
||||
|
|
@ -25,9 +25,11 @@ final class CoreContext : ObservableObject {
|
|||
|
||||
var mCore: Core!
|
||||
var mRegistrationDelegate : CoreDelegate!
|
||||
var mConfigurationDelegate : CoreDelegate!
|
||||
|
||||
var coreVersion: String = Core.getVersion
|
||||
@Published var loggedIn : Bool = false
|
||||
@Published var loggedIn : Bool = false
|
||||
@Published var configuringSuccessful : String = ""
|
||||
|
||||
private init() {}
|
||||
|
||||
|
|
@ -41,17 +43,30 @@ final class CoreContext : ObservableObject {
|
|||
|
||||
// Create a Core listener to listen for the callback we need
|
||||
// In this case, we want to know about the account registration status
|
||||
mRegistrationDelegate = CoreDelegateStub(onAccountRegistrationStateChanged: { (core: Core, account: Account, state: RegistrationState, message: String) in
|
||||
|
||||
mRegistrationDelegate =
|
||||
CoreDelegateStub(
|
||||
onConfiguringStatus: { (core: Core, state: Config.ConfiguringState, message: String) in
|
||||
NSLog("New configuration state is \(state) = \(message)\n")
|
||||
if (state == .Successful) {
|
||||
self.configuringSuccessful = "Successful"
|
||||
} else {
|
||||
self.configuringSuccessful = "Failed"
|
||||
}
|
||||
},
|
||||
|
||||
// If account has been configured correctly, we will go through Progress and Ok states
|
||||
// Otherwise, we will be Failed.
|
||||
NSLog("New registration state is \(state) for user id \( String(describing: account.params?.identityAddress?.asString()))\n")
|
||||
if (state == .Ok) {
|
||||
self.loggedIn = true
|
||||
} else if (state == .Cleared) {
|
||||
self.loggedIn = false
|
||||
onAccountRegistrationStateChanged: { (core: Core, account: Account, state: RegistrationState, message: String) in
|
||||
// If account has been configured correctly, we will go through Progress and Ok states
|
||||
// Otherwise, we will be Failed.
|
||||
NSLog("New registration state is \(state) for user id \( String(describing: account.params?.identityAddress?.asString()))\n")
|
||||
if (state == .Ok) {
|
||||
self.loggedIn = true
|
||||
} else if (state == .Cleared) {
|
||||
self.loggedIn = false
|
||||
}
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
mCore.addDelegate(delegate: mRegistrationDelegate)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,12 +22,14 @@ import SwiftUI
|
|||
@main
|
||||
struct LinphoneApp: App {
|
||||
|
||||
@ObservedObject private var coreContext = CoreContext.shared
|
||||
@State private var isActive = false
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
if isActive {
|
||||
ContentView(sharedMainViewModel: SharedMainViewModel())
|
||||
.toast(isShowing: $coreContext.configuringSuccessful)
|
||||
}else {
|
||||
SplashScreen(isActive: $isActive)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,6 +155,12 @@
|
|||
},
|
||||
"Interoperable mode" : {
|
||||
|
||||
},
|
||||
"Invalid QR code!" : {
|
||||
|
||||
},
|
||||
"Invalide URI" : {
|
||||
|
||||
},
|
||||
"Linphone" : {
|
||||
|
||||
|
|
@ -190,6 +196,9 @@
|
|||
},
|
||||
"Personnalize your profil mode" : {
|
||||
|
||||
},
|
||||
"QR code validated!" : {
|
||||
|
||||
},
|
||||
"Register" : {
|
||||
|
||||
|
|
|
|||
|
|
@ -150,32 +150,33 @@ struct LoginFragment: View {
|
|||
}
|
||||
}
|
||||
.padding(.bottom, 10)
|
||||
|
||||
Button(action: {
|
||||
|
||||
}) {
|
||||
HStack {
|
||||
Image("qr-code")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.orange_main_500)
|
||||
.frame(width: 20, height: 20)
|
||||
|
||||
Text("Scan QR code")
|
||||
.default_text_style_orange_600(styleSize: 20)
|
||||
.frame(height: 35)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.vertical, 10)
|
||||
.cornerRadius(60)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 60)
|
||||
.inset(by: 0.5)
|
||||
.stroke(Color.orange_main_500, lineWidth: 1)
|
||||
)
|
||||
.padding(.bottom)
|
||||
|
||||
NavigationLink(destination: {
|
||||
QrCodeScannerFragment()
|
||||
}, label: {
|
||||
HStack {
|
||||
Image("qr-code")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.orange_main_500)
|
||||
.frame(width: 20, height: 20)
|
||||
|
||||
Text("Scan QR code")
|
||||
.default_text_style_orange_600(styleSize: 20)
|
||||
.frame(height: 35)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
})
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.vertical, 10)
|
||||
.cornerRadius(60)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 60)
|
||||
.inset(by: 0.5)
|
||||
.stroke(Color.orange_main_500, lineWidth: 1)
|
||||
)
|
||||
.padding(.bottom)
|
||||
|
||||
NavigationLink(destination: {
|
||||
ThirdPartySipAccountWarningFragment(accountLoginViewModel: accountLoginViewModel)
|
||||
|
|
@ -231,6 +232,7 @@ struct LoginFragment: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
57
Linphone/UI/Assistant/Fragments/QrCodeScannerFragment.swift
Normal file
57
Linphone/UI/Assistant/Fragments/QrCodeScannerFragment.swift
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// QrCodeScannerFragment.swift
|
||||
// Linphone
|
||||
//
|
||||
// Created by Benoît Martins on 05/10/2023.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct QrCodeScannerFragment: View {
|
||||
|
||||
@ObservedObject private var coreContext = CoreContext.shared
|
||||
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
@State var scanResult = "Scan a QR code"
|
||||
|
||||
var body: some View {
|
||||
ZStack(alignment: .top) {
|
||||
QRScanner(result: $scanResult)
|
||||
|
||||
Text(scanResult)
|
||||
.default_text_style_white_800(styleSize: 20)
|
||||
.padding(.top, 175)
|
||||
|
||||
HStack{
|
||||
Button {
|
||||
dismiss()
|
||||
} label: {
|
||||
Image("caret-left")
|
||||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.white)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
}
|
||||
.padding()
|
||||
.padding(.top, 50)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
.navigationBarHidden(true)
|
||||
|
||||
if coreContext.configuringSuccessful == "Successful" {
|
||||
ZStack{
|
||||
|
||||
}.onAppear {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
QrCodeScannerFragment()
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ struct ThirdPartySipAccountLoginFragment: View {
|
|||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.gray_main2_500)
|
||||
.frame(width: 20, height: 20, alignment: .leading)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.top, -65)
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ struct ThirdPartySipAccountWarningFragment: View {
|
|||
.renderingMode(.template)
|
||||
.resizable()
|
||||
.foregroundStyle(Color.gray_main2_500)
|
||||
.frame(width: 20, height: 20, alignment: .leading)
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
.padding(.top, -65)
|
||||
.onTapGesture {
|
||||
withAnimation {
|
||||
|
|
@ -175,6 +175,7 @@ struct ThirdPartySipAccountWarningFragment: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
.navigationBarHidden(true)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
77
Linphone/UI/Assistant/Viewmodel/QRScanner.swift
Normal file
77
Linphone/UI/Assistant/Viewmodel/QRScanner.swift
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// QRScanner.swift
|
||||
// Linphone
|
||||
//
|
||||
// Created by Benoît Martins on 05/10/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import AVFoundation
|
||||
|
||||
struct QRScanner: UIViewControllerRepresentable {
|
||||
|
||||
@Binding var result: String
|
||||
|
||||
func makeUIViewController(context: Context) -> QRScannerController {
|
||||
let controller = QRScannerController()
|
||||
controller.delegate = context.coordinator
|
||||
|
||||
return controller
|
||||
}
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator($result)
|
||||
}
|
||||
|
||||
func updateUIViewController(_ uiViewController: QRScannerController, context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
class Coordinator: NSObject, AVCaptureMetadataOutputObjectsDelegate {
|
||||
|
||||
private var coreContext = CoreContext.shared
|
||||
|
||||
@Binding var scanResult: String
|
||||
private var lastResult: String = ""
|
||||
|
||||
init(_ scanResult: Binding<String>) {
|
||||
self._scanResult = scanResult
|
||||
}
|
||||
|
||||
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
|
||||
|
||||
// Check if the metadataObjects array is not nil and it contains at least one object.
|
||||
if metadataObjects.count == 0 {
|
||||
scanResult = "Scan a QR code"
|
||||
return
|
||||
}
|
||||
|
||||
// Get the metadata object.
|
||||
let metadataObj = metadataObjects[0] as! AVMetadataMachineReadableCodeObject
|
||||
|
||||
if metadataObj.type == AVMetadataObject.ObjectType.qr,
|
||||
let result = metadataObj.stringValue {
|
||||
if !result.isEmpty && result != lastResult {
|
||||
if let url = NSURL(string: result) {
|
||||
if UIApplication.shared.canOpenURL(url as URL) {
|
||||
lastResult = result
|
||||
//scanResult = result
|
||||
do {
|
||||
try coreContext.mCore.setProvisioninguri(newValue: result)
|
||||
coreContext.mCore.stop()
|
||||
try coreContext.mCore.start()
|
||||
}catch {
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
coreContext.configuringSuccessful = "Invalide URI"
|
||||
}
|
||||
} else {
|
||||
coreContext.configuringSuccessful = "Invalide URI"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
70
Linphone/UI/Main/Fragments/ToastView.swift
Normal file
70
Linphone/UI/Main/Fragments/ToastView.swift
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// ToastView.swift
|
||||
// Linphone
|
||||
//
|
||||
// Created by Benoît Martins on 06/10/2023.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ToastView: ViewModifier {
|
||||
|
||||
@Binding var isShowing: String
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
ZStack {
|
||||
content
|
||||
toastView
|
||||
}
|
||||
}
|
||||
|
||||
private var toastView: some View {
|
||||
VStack {
|
||||
if !isShowing.isEmpty {
|
||||
HStack {
|
||||
Image(isShowing == "Successful" ? "success" : "danger")
|
||||
.resizable()
|
||||
.frame(width: 25, height: 25, alignment: .leading)
|
||||
|
||||
Text(isShowing == "Successful" ? "QR code validated!" : (isShowing == "Failed" ? "Invalid QR code!" : "Invalide URI"))
|
||||
.multilineTextAlignment(.center)
|
||||
.foregroundStyle(isShowing == "Successful" ? Color.green_success_500 : Color.red_danger_500)
|
||||
.default_text_style(styleSize: 15)
|
||||
.padding(8)
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
.frame(height: 40)
|
||||
.background(.white)
|
||||
.cornerRadius(50)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 50)
|
||||
.inset(by: 0.5)
|
||||
.stroke(isShowing == "Successful" ? Color.green_success_500 : Color.red_danger_500, lineWidth: 1)
|
||||
)
|
||||
.onTapGesture {
|
||||
isShowing = ""
|
||||
}
|
||||
.onAppear {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
|
||||
isShowing = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.padding(.horizontal, 16)
|
||||
.padding(.bottom, 18)
|
||||
.animation(.linear(duration: 0.3), value: isShowing)
|
||||
.transition(.opacity)
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
func toast(isShowing: Binding<String>) -> some View {
|
||||
self.modifier(ToastView(isShowing: isShowing))
|
||||
}
|
||||
}
|
||||
|
||||
//#Preview {
|
||||
//ToastView()
|
||||
//}
|
||||
|
|
@ -118,14 +118,14 @@ struct WelcomeView: View{
|
|||
}
|
||||
|
||||
if self.isShowPopup {
|
||||
PopupView(isShowPopup: $isShowPopup, title: Text("Conditions de service"), content: Text("En continuant, vous acceptez ces conditions, \(Text("[notre politique de confidentialité](https://linphone.org/privacy-policy)").underline()) et \(Text("[nos conditions d’utilisation](https://linphone.org/general-terms)").underline())."), titleFirstButton: Text("Deny all"), actionFirstButton: {self.isShowPopup.toggle()}, titleSecondButton: Text("Accept all"), actionSecondButton: {permissionManager.photoLibraryRequestPermission()})
|
||||
PopupView(isShowPopup: $isShowPopup, title: Text("Conditions de service"), content: Text("En continuant, vous acceptez ces conditions, \(Text("[notre politique de confidentialité](https://linphone.org/privacy-policy)").underline()) et \(Text("[nos conditions d’utilisation](https://linphone.org/general-terms)").underline())."), titleFirstButton: Text("Deny all"), actionFirstButton: {self.isShowPopup.toggle()}, titleSecondButton: Text("Accept all"), actionSecondButton: {permissionManager.cameraRequestPermission()})
|
||||
.background(.black.opacity(0.65))
|
||||
.onTapGesture {
|
||||
self.isShowPopup.toggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
.onReceive(permissionManager.$photoLibraryPermissionGranted, perform: { (granted) in
|
||||
.onReceive(permissionManager.$cameraPermissionGranted, perform: { (granted) in
|
||||
if granted {
|
||||
withAnimation {
|
||||
sharedMainViewModel.changeGeneralTerms()
|
||||
|
|
|
|||
64
Linphone/Utils/QRScannerController.swift
Normal file
64
Linphone/Utils/QRScannerController.swift
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// QRScannerController.swift
|
||||
// Linphone
|
||||
//
|
||||
// Created by Benoît Martins on 05/10/2023.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import AVFoundation
|
||||
|
||||
class QRScannerController: UIViewController {
|
||||
var captureSession = AVCaptureSession()
|
||||
var videoPreviewLayer: AVCaptureVideoPreviewLayer?
|
||||
var qrCodeFrameView: UIView?
|
||||
|
||||
var delegate: AVCaptureMetadataOutputObjectsDelegate?
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// Get the back-facing camera for capturing videos
|
||||
guard let captureDevice = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: .back) else {
|
||||
print("Failed to get the camera device")
|
||||
return
|
||||
}
|
||||
|
||||
let videoInput: AVCaptureDeviceInput
|
||||
|
||||
do {
|
||||
// Get an instance of the AVCaptureDeviceInput class using the previous device object.
|
||||
videoInput = try AVCaptureDeviceInput(device: captureDevice)
|
||||
|
||||
} catch {
|
||||
// If any error occurs, simply print it out and don't continue any more.
|
||||
print(error)
|
||||
return
|
||||
}
|
||||
|
||||
// Set the input device on the capture session.
|
||||
captureSession.addInput(videoInput)
|
||||
|
||||
// Initialize a AVCaptureMetadataOutput object and set it as the output device to the capture session.
|
||||
let captureMetadataOutput = AVCaptureMetadataOutput()
|
||||
captureSession.addOutput(captureMetadataOutput)
|
||||
|
||||
// Set delegate and use the default dispatch queue to execute the call back
|
||||
captureMetadataOutput.setMetadataObjectsDelegate(delegate, queue: DispatchQueue.main)
|
||||
captureMetadataOutput.metadataObjectTypes = [ .qr ]
|
||||
|
||||
// Initialize the video preview layer and add it as a sublayer to the viewPreview view's layer.
|
||||
videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
|
||||
videoPreviewLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
|
||||
videoPreviewLayer?.frame = view.layer.bounds
|
||||
view.layer.addSublayer(videoPreviewLayer!)
|
||||
|
||||
// Start video capture.
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
self.captureSession.startRunning()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue