Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Menu
Open sidebar
elixxir
xx messenger iOS
Commits
9ff96751
Commit
9ff96751
authored
Aug 25, 2022
by
Bruno Muniz
🍎
Browse files
Merge branch 'development' into 'master'
Releasing v1.1.5 (214) See merge request
!71
parents
731cef6d
d074afa3
Changes
98
Expand all
Hide whitespace changes
Inline
Side-by-side
.swiftpm/xcode/xcshareddata/xcschemes/ChatFeature.xcscheme
0 → 100644
View file @
9ff96751
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion =
"1340"
version =
"1.3"
>
<BuildAction
parallelizeBuildables =
"YES"
buildImplicitDependencies =
"YES"
>
<BuildActionEntries>
<BuildActionEntry
buildForTesting =
"YES"
buildForRunning =
"YES"
buildForProfiling =
"YES"
buildForArchiving =
"YES"
buildForAnalyzing =
"YES"
>
<BuildableReference
BuildableIdentifier =
"primary"
BlueprintIdentifier =
"ChatFeature"
BuildableName =
"ChatFeature"
BlueprintName =
"ChatFeature"
ReferencedContainer =
"container:"
>
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration =
"Debug"
selectedDebuggerIdentifier =
"Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier =
"Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv =
"YES"
codeCoverageEnabled =
"YES"
>
<Testables>
<TestableReference
skipped =
"NO"
>
<BuildableReference
BuildableIdentifier =
"primary"
BlueprintIdentifier =
"ChatFeatureTests"
BuildableName =
"ChatFeatureTests"
BlueprintName =
"ChatFeatureTests"
ReferencedContainer =
"container:"
>
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration =
"Debug"
selectedDebuggerIdentifier =
"Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier =
"Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle =
"0"
useCustomWorkingDirectory =
"NO"
ignoresPersistentStateOnLaunch =
"NO"
debugDocumentVersioning =
"YES"
debugServiceExtension =
"internal"
allowLocationSimulation =
"YES"
>
</LaunchAction>
<ProfileAction
buildConfiguration =
"Release"
shouldUseLaunchSchemeArgsEnv =
"YES"
savedToolIdentifier =
""
useCustomWorkingDirectory =
"NO"
debugDocumentVersioning =
"YES"
>
<MacroExpansion>
<BuildableReference
BuildableIdentifier =
"primary"
BlueprintIdentifier =
"ChatFeature"
BuildableName =
"ChatFeature"
BlueprintName =
"ChatFeature"
ReferencedContainer =
"container:"
>
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration =
"Debug"
>
</AnalyzeAction>
<ArchiveAction
buildConfiguration =
"Release"
revealArchiveInOrganizer =
"YES"
>
</ArchiveAction>
</Scheme>
App/client-ios.xcodeproj/xcshareddata/xcschemes/Release.xcscheme
View file @
9ff96751
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion =
"1200"
version =
"1.
3
"
>
version =
"1.
7
"
>
<BuildAction
parallelizeBuildables =
"YES"
buildImplicitDependencies =
"YES"
>
...
...
@@ -52,6 +52,24 @@
migratedStopOnEveryIssue =
"YES"
debugServiceExtension =
"internal"
allowLocationSimulation =
"YES"
>
<PreActions>
<ExecutionAction
ActionType =
"Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction"
>
<ActionContent
title =
"Run Script"
scriptText =
"#!/bin/sh /usr/libexec/PlistBuddy -c "Set :isReportingOptional YES" "${SRCROOT}/client-ios/Resources/Info.plist" "
>
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier =
"primary"
BlueprintIdentifier =
"02FDD06121EDA39A000F1286"
BuildableName =
"client-ios.app"
BlueprintName =
"client-ios"
ReferencedContainer =
"container:client-ios.xcodeproj"
>
</BuildableReference>
</EnvironmentBuildable>
</ActionContent>
</ExecutionAction>
</PreActions>
<BuildableProductRunnable
runnableDebuggingMode =
"0"
>
<BuildableReference
...
...
@@ -91,5 +109,23 @@
<ArchiveAction
buildConfiguration =
"Release"
revealArchiveInOrganizer =
"YES"
>
<PreActions>
<ExecutionAction
ActionType =
"Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction"
>
<ActionContent
title =
"Run Script"
scriptText =
"#!/bin/sh /usr/libexec/PlistBuddy -c "Set :isReportingOptional NO" "${SRCROOT}/client-ios/Resources/Info.plist" "
>
<EnvironmentBuildable>
<BuildableReference
BuildableIdentifier =
"primary"
BlueprintIdentifier =
"02FDD06121EDA39A000F1286"
BuildableName =
"client-ios.app"
BlueprintName =
"client-ios"
ReferencedContainer =
"container:client-ios.xcodeproj"
>
</BuildableReference>
</EnvironmentBuildable>
</ActionContent>
</ExecutionAction>
</PreActions>
</ArchiveAction>
</Scheme>
App/client-ios/Resources/Info.plist
View file @
9ff96751
...
...
@@ -34,10 +34,10 @@
</dict>
<dict>
<key>
CFBundleURLName
</key>
<string>
xx
messenger
</string>
<string>
xx
network
</string>
<key>
CFBundleURLSchemes
</key>
<array>
<string>
xx
messenger
</string>
<string>
xx
network
</string>
</array>
</dict>
<dict>
...
...
@@ -104,5 +104,7 @@
</array>
<key>
UIViewControllerBasedStatusBarAppearance
</key>
<true/>
<key>
isReportingOptional
</key>
<false/>
</dict>
</plist>
App/client-ios/Resources/client-ios.entitlements
View file @
9ff96751
...
...
@@ -4,6 +4,10 @@
<dict>
<key>
aps-environment
</key>
<string>
development
</string>
<key>
com.apple.developer.associated-domains
</key>
<array>
<string>
applinks:elixxir.io
</string>
</array>
<key>
com.apple.developer.icloud-container-identifiers
</key>
<array>
<string>
iCloud.xxm-cloud
</string>
...
...
Package.swift
View file @
9ff96751
This diff is collapsed.
Click to expand it.
Sources/App/AppDelegate.swift
View file @
9ff96751
...
...
@@ -144,6 +144,35 @@ public class AppDelegate: UIResponder, UIApplicationDelegate {
)
->
Bool
{
dropboxService
.
handleOpenUrl
(
url
)
}
public
func
application
(
_
application
:
UIApplication
,
continue
userActivity
:
NSUserActivity
,
restorationHandler
:
@escaping
([
UIUserActivityRestoring
]?)
->
Void
)
->
Bool
{
guard
userActivity
.
activityType
==
NSUserActivityTypeBrowsingWeb
,
let
incomingURL
=
userActivity
.
webpageURL
,
let
username
=
getUsernameFromInvitationDeepLink
(
incomingURL
)
else
{
return
false
}
let
router
=
try!
DependencyInjection
.
Container
.
shared
.
resolve
()
as
PushRouter
router
.
navigateTo
(
.
search
(
username
:
username
),
{})
return
true
}
}
func
getUsernameFromInvitationDeepLink
(
_
url
:
URL
)
->
String
?
{
if
let
components
=
URLComponents
(
url
:
url
,
resolvingAgainstBaseURL
:
false
),
components
.
scheme
==
"https"
,
components
.
host
==
"elixxir.io"
,
components
.
path
==
"/connect"
,
let
queryItem
=
components
.
queryItems
?
.
first
(
where
:
{
$0
.
name
==
"username"
}),
let
username
=
queryItem
.
value
{
return
username
}
return
nil
}
// MARK: Notifications
...
...
Sources/App/DependencyRegistrator.swift
View file @
9ff96751
...
...
@@ -26,6 +26,7 @@ import CrashReporting
import
NetworkMonitor
import
DropboxFeature
import
VersionChecking
import
ReportingFeature
import
GoogleDriveFeature
import
DependencyInjection
...
...
@@ -34,6 +35,7 @@ import DependencyInjection
import
ScanFeature
import
ChatFeature
import
MenuFeature
import
TermsFeature
import
BackupFeature
import
SearchFeature
import
LaunchFeature
...
...
@@ -79,6 +81,7 @@ struct DependencyRegistrator {
container
.
register
(
XXLogger
.
live
())
container
.
register
(
CrashReporter
.
live
)
container
.
register
(
VersionChecker
.
live
())
container
.
register
(
ReportingStatus
.
live
())
container
.
register
(
XXNetwork
<
BindingsClient
>
()
as
XXNetworking
)
container
.
register
(
NetworkMonitor
()
as
NetworkMonitoring
)
...
...
@@ -101,6 +104,11 @@ struct DependencyRegistrator {
static
private
func
registerCommonDependencies
()
{
container
.
register
(
Voxophone
())
container
.
register
(
BackupService
())
container
.
register
(
MakeAppScreenshot
.
live
)
container
.
register
(
SendReport
.
live
)
container
.
register
(
FetchBannedList
.
live
)
container
.
register
(
ProcessBannedList
.
live
)
container
.
register
(
MakeReportDrawer
.
live
)
// MARK: Isolated
...
...
@@ -111,8 +119,17 @@ struct DependencyRegistrator {
// MARK: Coordinators
container
.
register
(
TermsCoordinator
.
live
(
usernameFactory
:
OnboardingUsernameController
.
init
(
_
:),
chatListFactory
:
ChatListController
.
init
)
)
container
.
register
(
LaunchCoordinator
(
termsFactory
:
TermsConditionsController
.
init
(
_
:),
searchFactory
:
SearchContainerController
.
init
,
requestsFactory
:
RequestsContainerController
.
init
,
chatListFactory
:
ChatListController
.
init
,
onboardingFactory
:
OnboardingStartController
.
init
(
_
:),
...
...
@@ -205,6 +222,7 @@ struct DependencyRegistrator {
searchFactory
:
SearchContainerController
.
init
,
welcomeFactory
:
OnboardingWelcomeController
.
init
,
chatListFactory
:
ChatListController
.
init
,
termsFactory
:
TermsConditionsController
.
init
(
_
:),
usernameFactory
:
OnboardingUsernameController
.
init
(
_
:),
restoreListFactory
:
RestoreListController
.
init
(
_
:),
successFactory
:
OnboardingSuccessController
.
init
(
_
:),
...
...
@@ -250,38 +268,3 @@ struct DependencyRegistrator {
)
as
ChatListCoordinating
)
}
}
extension
PushRouter
{
static
func
live
(
navigationController
:
UINavigationController
)
->
PushRouter
{
PushRouter
{
route
,
completion
in
if
let
launchController
=
navigationController
.
viewControllers
.
last
as?
LaunchController
{
launchController
.
pendingPushRoute
=
route
}
else
{
switch
route
{
case
.
requests
:
if
(
navigationController
.
viewControllers
.
last
as?
RequestsContainerController
)
==
nil
{
navigationController
.
setViewControllers
([
RequestsContainerController
()],
animated
:
true
)
}
case
.
contactChat
(
id
:
let
id
):
if
let
session
=
try
?
DependencyInjection
.
Container
.
shared
.
resolve
()
as
SessionType
,
let
contact
=
try
?
session
.
dbManager
.
fetchContacts
(
.
init
(
id
:
[
id
]))
.
first
{
navigationController
.
setViewControllers
([
ChatListController
(),
SingleChatController
(
contact
)
],
animated
:
true
)
}
case
.
groupChat
(
id
:
let
id
):
if
let
session
=
try
?
DependencyInjection
.
Container
.
shared
.
resolve
()
as
SessionType
,
let
info
=
try
?
session
.
dbManager
.
fetchGroupInfos
(
.
init
(
groupId
:
id
))
.
first
{
navigationController
.
setViewControllers
([
ChatListController
(),
GroupChatController
(
info
)
],
animated
:
true
)
}
}
}
completion
()
}
}
}
Sources/App/PushRouter.swift
0 → 100644
View file @
9ff96751
import
UIKit
import
PushFeature
import
Integration
import
ChatFeature
import
SearchFeature
import
LaunchFeature
import
ChatListFeature
import
RequestsFeature
import
DependencyInjection
extension
PushRouter
{
static
func
live
(
navigationController
:
UINavigationController
)
->
PushRouter
{
PushRouter
{
route
,
completion
in
if
let
launchController
=
navigationController
.
viewControllers
.
last
as?
LaunchController
{
launchController
.
pendingPushRoute
=
route
}
else
{
switch
route
{
case
.
requests
:
if
!
(
navigationController
.
viewControllers
.
last
is
RequestsContainerController
)
{
navigationController
.
setViewControllers
([
RequestsContainerController
()],
animated
:
true
)
}
case
.
search
(
username
:
let
username
):
if
let
_
=
try
?
DependencyInjection
.
Container
.
shared
.
resolve
()
as
SessionType
,
!
(
navigationController
.
viewControllers
.
last
is
SearchContainerController
)
{
navigationController
.
setViewControllers
([
ChatListController
(),
SearchContainerController
(
username
)
],
animated
:
true
)
}
case
.
contactChat
(
id
:
let
id
):
if
let
session
=
try
?
DependencyInjection
.
Container
.
shared
.
resolve
()
as
SessionType
,
let
contact
=
try
?
session
.
dbManager
.
fetchContacts
(
.
init
(
id
:
[
id
]))
.
first
{
navigationController
.
setViewControllers
([
ChatListController
(),
SingleChatController
(
contact
)
],
animated
:
true
)
}
case
.
groupChat
(
id
:
let
id
):
if
let
session
=
try
?
DependencyInjection
.
Container
.
shared
.
resolve
()
as
SessionType
,
let
info
=
try
?
session
.
dbManager
.
fetchGroupInfos
(
.
init
(
groupId
:
id
))
.
first
{
navigationController
.
setViewControllers
([
ChatListController
(),
GroupChatController
(
info
)
],
animated
:
true
)
}
}
}
completion
()
}
}
}
Sources/BackupFeature/Controllers/BackupController.swift
View file @
9ff96751
...
...
@@ -11,6 +11,13 @@ public final class BackupController: UIViewController {
private
let
viewModel
=
BackupViewModel
.
live
()
private
var
cancellables
=
Set
<
AnyCancellable
>
()
public
override
func
viewWillAppear
(
_
animated
:
Bool
)
{
super
.
viewWillAppear
(
animated
)
navigationItem
.
backButtonTitle
=
""
navigationController
?
.
navigationBar
.
customize
(
backgroundColor
:
Asset
.
neutralWhite
.
color
)
}
public
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
view
.
backgroundColor
=
Asset
.
neutralWhite
.
color
...
...
@@ -21,19 +28,12 @@ public final class BackupController: UIViewController {
}
private
func
setupNavigationBar
()
{
navigationItem
.
backButtonTitle
=
""
let
title
=
UILabel
()
title
.
text
=
Localized
.
Backup
.
header
title
.
textColor
=
Asset
.
neutralActive
.
color
title
.
font
=
Fonts
.
Mulish
.
semiBold
.
font
(
size
:
18.0
)
let
back
=
UIButton
.
back
()
back
.
addTarget
(
self
,
action
:
#selector(
didTapBack
)
,
for
:
.
touchUpInside
)
navigationItem
.
leftBarButtonItem
=
UIBarButtonItem
(
customView
:
UIStackView
(
arrangedSubviews
:
[
back
,
title
])
)
navigationItem
.
leftBarButtonItem
=
UIBarButtonItem
(
customView
:
title
)
navigationItem
.
leftItemsSupplementBackButton
=
true
}
private
func
setupBindings
()
{
...
...
@@ -70,8 +70,4 @@ public final class BackupController: UIViewController {
}
}
}
@objc
private
func
didTapBack
()
{
navigationController
?
.
popViewController
(
animated
:
true
)
}
}
Sources/BackupFeature/Controllers/BackupPassphraseController.swift
View file @
9ff96751
...
...
@@ -2,7 +2,6 @@ import UIKit
import
Shared
import
Combine
import
InputField
import
ScrollViewController
public
final
class
BackupPassphraseController
:
UIViewController
{
lazy
private
var
screenView
=
BackupPassphraseView
()
...
...
@@ -21,7 +20,6 @@ public final class BackupPassphraseController: UIViewController {
private
let
cancelClosure
:
EmptyClosure
private
let
stringClosure
:
StringClosure
private
var
cancellables
=
Set
<
AnyCancellable
>
()
private
let
keyboardListener
=
KeyboardFrameChangeListener
(
notificationCenter
:
.
default
)
public
init
(
_
cancelClosure
:
@escaping
EmptyClosure
,
...
...
@@ -35,66 +33,41 @@ public final class BackupPassphraseController: UIViewController {
required
init
?(
coder
:
NSCoder
)
{
nil
}
public
override
func
loadView
()
{
let
view
=
UIView
()
view
.
addSubview
(
screenView
)
screenView
.
snp
.
makeConstraints
{
make
in
make
.
top
.
equalToSuperview
()
make
.
left
.
equalToSuperview
()
make
.
right
.
equalToSuperview
()
make
.
bottom
.
equalToSuperview
()
.
offset
(
0
)
}
self
.
view
=
view
view
=
screenView
}
public
override
func
viewDidLoad
()
{
super
.
viewDidLoad
()
setupKeyboard
()
setupBindings
()
screenView
.
continueButton
.
isEnabled
=
false
}
private
func
setupKeyboard
()
{
keyboardListener
.
keyboardFrameWillChange
=
{
[
weak
self
]
keyboard
in
guard
let
self
=
self
else
{
return
}
let
inset
=
self
.
view
.
frame
.
height
-
self
.
view
.
convert
(
keyboard
.
frame
,
from
:
nil
)
.
minY
self
.
screenView
.
snp
.
updateConstraints
{
$0
.
bottom
.
equalToSuperview
()
.
offset
(
-
inset
)
}
self
.
view
.
setNeedsLayout
()
UIView
.
animate
(
withDuration
:
keyboard
.
animationDuration
)
{
self
.
view
.
layoutIfNeeded
()
}
}
}
private
func
setupBindings
()
{
screenView
.
inputField
.
returnPublisher
.
sink
{
[
unowned
self
]
in
screenView
.
inputField
.
endEditing
(
true
)
}
.
store
(
in
:
&
cancellables
)
screenView
.
cancelButton
.
publisher
(
for
:
.
touchUpInside
)
.
sink
{
[
unowned
self
]
in
dismiss
(
animated
:
true
)
{
self
.
cancelClosure
()
}}
.
store
(
in
:
&
cancellables
)
screenView
.
inputField
.
returnPublisher
.
sink
{
[
unowned
self
]
in
screenView
.
inputField
.
endEditing
(
true
)
}
.
store
(
in
:
&
cancellables
)
screenView
.
inputField
screenView
.
inputField
.
textPublisher
.
sink
{
[
unowned
self
]
in
passphrase
=
$0
.
trimmingCharacters
(
in
:
.
whitespacesAndNewlines
)
}
.
store
(
in
:
&
cancellables
)
.
sink
{
[
unowned
self
]
in
passphrase
=
$0
.
trimmingCharacters
(
in
:
.
whitespacesAndNewlines
)
}
.
store
(
in
:
&
cancellables
)
screenView
.
continueButton
.
publisher
(
for
:
.
touchUpInside
)
.
sink
{
[
unowned
self
]
in
dismiss
(
animated
:
true
)
{
self
.
stringClosure
(
self
.
passphrase
)
}
}
.
store
(
in
:
&
cancellables
)
screenView
.
continueButton
screenView
.
cancelButton
.
publisher
(
for
:
.
touchUpInside
)
.
sink
{
[
unowned
self
]
in
dismiss
(
animated
:
true
)
{
self
.
stringClosure
(
self
.
passphrase
)
}
dismiss
(
animated
:
true
)
{
self
.
cancelClosure
()
}
}
.
store
(
in
:
&
cancellables
)
}
}
Sources/BackupFeature/Coordinator/BackupCoordinator.swift
View file @
9ff96751
import
UIKit
import
Shared
import
Presentation
import
ScrollViewController
public
protocol
BackupCoordinating
{
func
toDrawer
(
...
...
@@ -16,12 +17,18 @@ public protocol BackupCoordinating {
}
public
struct
BackupCoordinator
:
BackupCoordinating
{
var
bottom
Presenter
:
Presenting
=
Bottom
Presenter
()
var
fullscreen
Presenter
:
Presenting
=
Fullscreen
Presenter
()
var
passphraseFactory
:
(
@escaping
EmptyClosure
,
@escaping
StringClosure
)
->
UIViewController
var
passphraseFactory
:
(
@escaping
EmptyClosure
,
@escaping
StringClosure
)
->
UIViewController
public
init
(
passphraseFactory
:
@escaping
(
@escaping
EmptyClosure
,
@escaping
StringClosure
)
->
UIViewController
passphraseFactory
:
@escaping
(
@escaping
EmptyClosure
,
@escaping
StringClosure
)
->
UIViewController
)
{
self
.
passphraseFactory
=
passphraseFactory
}
...
...
@@ -32,7 +39,8 @@ public extension BackupCoordinator {
_
screen
:
UIViewController
,
from
parent
:
UIViewController
)
{
bottomPresenter
.
present
(
screen
,
from
:
parent
)
let
target
=
ScrollViewController
.
embedding
(
screen
)
fullscreenPresenter
.
present
(
target
,
from
:
parent
)
}
func
toPassphrase
(
...
...
@@ -41,6 +49,21 @@ public extension BackupCoordinator {
passphraseClosure
:
@escaping
StringClosure
)
{
let
screen
=
passphraseFactory
(
cancelClosure
,
passphraseClosure
)
bottomPresenter
.
present
(
screen
,
from
:
parent
)
let
target
=
ScrollViewController
.
embedding
(
screen
)
fullscreenPresenter
.
present
(
target
,
from
:
parent
)
}
}
extension
ScrollViewController
{
static
func
embedding
(
_
viewController
:
UIViewController
)
->
ScrollViewController
{
let
scrollViewController
=
ScrollViewController
()
scrollViewController
.
addChild
(
viewController
)
scrollViewController
.
contentView
=
viewController
.
view
scrollViewController
.
wrapperView
.
handlesTouchesOutsideContent
=
false
scrollViewController
.
wrapperView
.
alignContentToBottom
=
true
scrollViewController
.
scrollView
.
bounces
=
false
viewController
.
didMove
(
toParent
:
scrollViewController
)
return
scrollViewController
}
}
Sources/BackupFeature/Views/BackupPassphraseView.swift
View file @
9ff96751
...
...
@@ -4,49 +4,62 @@ import InputField
final
class
BackupPassphraseView
:
UIView
{
let
titleLabel
=
UILabel
()
let
subtitleLabel
=
UILabel
()
let
inputField
=
InputField
()
let
stackView
=
UIStackView
()
let
continueButton
=
CapsuleButton
()
let
inputField
=
InputField
()
let
subtitleLabel
=
UILabel
()
let
cancelButton
=
CapsuleButton
()
let
continueButton
=
CapsuleButton
()
init
()
{
super
.
init
(
frame
:
.
zero
)
setup
()
}
required
init
?(
coder
:
NSCoder
)
{
nil
}
private
func
setup
()
{
layer
.
cornerRadius
=
40
backgroundColor
=
Asset
.
neutralWhite
.
color
layer
.
maskedCorners
=
[
.
layerMinXMinYCorner
,
.
layerMaxXMinYCorner
]
subtitleLabel
.
numberOfLines
=
0
titleLabel
.
textColor
=
Asset
.
neutralActive
.
color
subtitleLabel
.
textColor
=
Asset
.
neutralActive
.
color
setupInput
()
setupLabels
()