Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
enzevalos
enzevalos_iphone
Commits
b9a45c3e
Commit
b9a45c3e
authored
Apr 10, 2021
by
Oliver Wiese
Browse files
Merge branch '298-missing-backend-features-connections-for-ui'
Conflicts: enzevalos_iphone/SwiftUI/Compose/ComposeModel.swift
parents
348cff0a
d8f21af3
Changes
36
Hide whitespace changes
Inline
Side-by-side
enzevalos_iphone.xcodeproj/project.pbxproj
View file @
b9a45c3e
...
...
@@ -45,6 +45,7 @@
4707092D2189C74200DF71A3
/* bobSecret.asc in Resources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
4707092B2189C74200DF71A3
/* bobSecret.asc */
;
};
4707092E2189C74200DF71A3
/* alicePublic.asc in Resources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
4707092C2189C74200DF71A3
/* alicePublic.asc */
;
};
470709302189E1C100DF71A3
/* enc+signedThunderbird.eml in Resources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
4707092F2189E1C000DF71A3
/* enc+signedThunderbird.eml */
;
};
4709769626220659002436E2
/* SimpleMailRowView.swift in Sources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
4709769526220659002436E2
/* SimpleMailRowView.swift */
;
};
47184C3922F0D8F200712A7A
/* CFNetwork.framework in Frameworks */
=
{
isa
=
PBXBuildFile
;
fileRef
=
47184C3822F0D8F200712A7A
/* CFNetwork.framework */
;
};
471876F7223FACA900912135
/* BobPWTEST1234.asc in Resources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
471876F5223FACA900912135
/* BobPWTEST1234.asc */
;
};
471876F8223FACA900912135
/* BobWithoutPW.asc in Resources */
=
{
isa
=
PBXBuildFile
;
fileRef
=
471876F6223FACA900912135
/* BobWithoutPW.asc */
;
};
...
...
@@ -325,6 +326,7 @@
4707092B2189C74200DF71A3
/* bobSecret.asc */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
text
;
path
=
bobSecret.asc
;
sourceTree
=
"<group>"
;
};
4707092C2189C74200DF71A3
/* alicePublic.asc */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
text
;
path
=
alicePublic.asc
;
sourceTree
=
"<group>"
;
};
4707092F2189E1C000DF71A3
/* enc+signedThunderbird.eml */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
text
;
path
=
"enc+signedThunderbird.eml"
;
sourceTree
=
"<group>"
;
};
4709769526220659002436E2
/* SimpleMailRowView.swift */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
sourcecode.swift
;
path
=
SimpleMailRowView.swift
;
sourceTree
=
"<group>"
;
};
47184C3822F0D8F200712A7A
/* CFNetwork.framework */
=
{
isa
=
PBXFileReference
;
lastKnownFileType
=
wrapper.framework
;
name
=
CFNetwork.framework
;
path
=
System/Library/Frameworks/CFNetwork.framework
;
sourceTree
=
SDKROOT
;
};
471876F5223FACA900912135
/* BobPWTEST1234.asc */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
text
;
path
=
BobPWTEST1234.asc
;
sourceTree
=
"<group>"
;
};
471876F6223FACA900912135
/* BobWithoutPW.asc */
=
{
isa
=
PBXFileReference
;
fileEncoding
=
4
;
lastKnownFileType
=
text
;
path
=
BobWithoutPW.asc
;
sourceTree
=
"<group>"
;
};
...
...
@@ -1045,6 +1047,7 @@
isa
=
PBXGroup
;
children
=
(
477120C1254C676000B28C64
/* ContactView.swift */
,
4709769526220659002436E2
/* SimpleMailRowView.swift */
,
32261742260C7CE60068CBD4
/* ContactMailListView.swift */
,
);
path
=
Contact
;
...
...
@@ -1977,6 +1980,7 @@
47FAE3492524FB58005A1BCB
/* AddressRecord.swift in Sources */
,
4775D7AA243F0E260052F2CC
/* SimulatorData.swift in Sources */
,
47C8225324379EAE005BCE73
/* AttachmentsViewMain.swift in Sources */
,
4709769626220659002436E2
/* SimpleMailRowView.swift in Sources */
,
678942612430C3D600C746D1
/* Typosquatting.swift in Sources */
,
47C112CA2531E9B000621A07
/* AttachmentRecord.swift in Sources */
,
476406982416B54D00C7D426
/* CircleImage.swift in Sources */
,
...
...
enzevalos_iphone/AuthenticationView.swift
View file @
b9a45c3e
...
...
@@ -211,12 +211,11 @@ struct LoginAdvancedSection: View{
ForEach
(
0
..<
encryptionOptions
.
count
)
{
i
in
Text
(
self
.
encryptionOptions
[
i
])
.
tag
(
i
)
.
onTapGesture
{
print
(
"Tap!"
)
if
!
s
{
self
.
imapEncryption
=
i
}
else
{
self
.
smtpEncryption
=
i
}
if
!
s
{
self
.
imapEncryption
=
i
}
else
{
self
.
smtpEncryption
=
i
}
}
}
}
...
...
enzevalos_iphone/ContactHandler.swift
View file @
b9a45c3e
...
...
@@ -24,7 +24,7 @@ import SwiftUI
// TODO: Mark displayname as from CNContact
class
ContactHandler
{
static
var
cartoons
=
tru
e
static
var
cartoons
=
fals
e
private
let
store
=
CNContactStore
()
static
let
handler
=
ContactHandler
()
...
...
enzevalos_iphone/MailHandler.swift
View file @
b9a45c3e
...
...
@@ -48,6 +48,10 @@
case
postcard
}
enum
FolderError
:
Error
{
case
WrongUidValidity
}
class
MailHandler
{
private
static
let
MAXMAILS
=
25
private
static
let
extraHeaders
=
Autocrypt
.
EXTRAHEADERS
...
...
@@ -164,7 +168,7 @@
// TODO SEND MAIL... later...
func
storeIMAP
(
mail
:
OutgoingMail
,
folder
:
String
,
callback
:
((
MailServerConnectionError
?)
->
Void
)?)
{
// 1. Test if folder exists
let
existFolderController
=
dataProvider
.
generateFetchedFolderResultsController
(
folderpath
:
folder
)
let
existFolderController
=
dataProvider
.
generateFetchedFolderResultsController
(
folderpath
:
folder
,
moc
:
nil
)
if
existFolderController
.
fetchedObjects
!=
nil
{
// 2. Store Mail in test
// We can always store encrypted data on the imap server because the user has a key pair and it is users imap account.
...
...
@@ -191,7 +195,7 @@
return
}
// Create folder on local
let
folderProperty
=
FolderProperties
(
delimiter
:
nil
,
uidValidity
:
nil
,
lastUpdate
:
nil
,
maxUID
:
nil
,
minUID
:
nil
,
path
:
folder
)
let
folderProperty
=
FolderProperties
(
delimiter
:
nil
,
uidValidity
:
nil
,
lastUpdate
:
nil
,
maxUID
:
nil
,
minUID
:
nil
,
path
:
folder
,
flags
:
0
)
dataProvider
.
importNewData
(
from
:
[
folderProperty
],
completionHandler
:
{
error
in
guard
error
==
nil
else
{
// TODO: Error handling
...
...
@@ -277,7 +281,7 @@
guard
IMAPSession
!=
nil
else
{
return
}
if
let
f
=
dataProvider
.
generateFetchedFolderResultsController
(
folderpath
:
folderName
)
.
fetchedObjects
?
.
first
{
if
let
f
=
dataProvider
.
generateFetchedFolderResultsController
(
folderpath
:
folderName
,
moc
:
nil
)
.
fetchedObjects
?
.
first
{
let
folderstatus
=
IMAPSession
?
.
folderStatusOperation
(
folderName
)
folderstatus
?
.
start
{[
unowned
self
]
(
error
,
status
)
->
Void
in
guard
error
==
nil
else
{
...
...
@@ -320,7 +324,7 @@
completionCallback
(
MailServerConnectionError
.
NoData
)
return
}
if
let
folder
=
dataProvider
.
generateFetchedFolderResultsController
(
folderpath
:
MailHandler
.
INBOX
)
.
fetchedObjects
?
.
first
{
if
let
folder
=
dataProvider
.
generateFetchedFolderResultsController
(
folderpath
:
MailHandler
.
INBOX
,
moc
:
nil
)
.
fetchedObjects
?
.
first
{
let
folderstatus
=
IMAPSession
?
.
folderStatusOperation
(
folder
.
path
)
folderstatus
?
.
start
{[
unowned
self
]
(
error
,
status
)
->
Void
in
guard
error
==
nil
else
{
...
...
@@ -344,7 +348,7 @@
completionCallback
(
0
,
completionHandler
)
return
}
if
let
folder
=
dataProvider
.
generateFetchedFolderResultsController
(
folderpath
:
MailHandler
.
INBOX
)
.
fetchedObjects
?
.
first
{
if
let
folder
=
dataProvider
.
generateFetchedFolderResultsController
(
folderpath
:
MailHandler
.
INBOX
,
moc
:
nil
)
.
fetchedObjects
?
.
first
{
let
folderstatus
=
IMAPSession
?
.
folderStatusOperation
(
folder
.
path
)
// Work only in background thread....
var
backgroundTaskID
:
Int
?
...
...
@@ -448,79 +452,96 @@
}
}
}
private
func
createFolders
(
of
paths
:
[
String
],
completionHandler
:
@escaping
(
_
error
:
Error
?)
->
Void
)
{
guard
let
session
=
IMAPSession
else
{
completionHandler
(
MailServerConnectionError
.
ConnectionError
)
return
}
session
.
fetchAllFoldersOperation
()?
.
start
({
error
,
folders
in
guard
error
!=
nil
else
{
completionHandler
(
error
)
return
}
var
myError
:
Error
?
=
nil
var
createFolders
=
[
String
]()
if
let
names
=
folders
?
.
map
({
$0
.
path
})
{
for
path
in
paths
{
if
!
names
.
contains
(
path
)
{
createFolders
.
append
(
path
)
}
}
}
let
myGroup
=
DispatchGroup
()
let
queue
=
DispatchQueue
(
label
:
"com.letterbox.mailhandler"
)
queue
.
async
{
for
path
in
createFolders
{
myGroup
.
enter
()
session
.
createFolderOperation
(
path
)?
.
start
({
error
in
myError
=
error
myGroup
.
leave
()
})
}
myGroup
.
notify
(
queue
:
queue
,
execute
:
{
completionHandler
(
myError
)
})
}
})
}
private
func
moveOnServer
(
uidValidity
:
UInt32
,
mails
:
[
UInt64
],
fromPath
:
String
,
toPath
:
String
,
completionHandler
:
@escaping
(
_
error
:
Error
?)
->
Void
)
{
guard
let
session
=
IMAPSession
else
{
completionHandler
(
MailServerConnectionError
.
ConnectionError
)
return
}
// 1. Check uid valilidity
session
.
folderInfoOperation
(
fromPath
)?
.
start
({
error
,
infos
in
guard
error
==
nil
,
let
infos
=
infos
else
{
completionHandler
(
error
)
return
}
guard
infos
.
uidValidity
==
uidValidity
else
{
completionHandler
(
FolderError
.
WrongUidValidity
)
return
}
// 2. Move mails if uid is valid
let
uidSet
=
MCOIndexSet
()
mails
.
forEach
({
uidSet
.
add
(
$0
)})
session
.
moveMessagesOperation
(
withFolder
:
fromPath
,
uids
:
uidSet
,
destFolder
:
toPath
)?
.
start
({(
error
,
_
)
in
guard
error
==
nil
else
{
session
.
copyMessagesOperation
(
withFolder
:
fromPath
,
uids
:
uidSet
,
destFolder
:
toPath
)?
.
start
({(
error
,
_
)
in
completionHandler
(
error
)
})
return
}
completionHandler
(
nil
)
return
})
})
}
func
move
(
mails
:
[
UInt64
],
fromPath
:
String
,
toPath
:
String
)
{
// 1. Check if we have to create a folder.
createFolders
(
of
:
[
fromPath
,
toPath
],
completionHandler
:
{
error
in
guard
error
==
nil
else
{
return
}
// 2. Move mail on server
guard
let
fromFolder
=
self
.
dataProvider
.
generateFetchedFolderResultsController
(
folderpath
:
fromPath
,
moc
:
nil
)
.
fetchedObjects
?
.
first
else
{
return
}
if
let
uidValidity
=
fromFolder
.
uidValidity
as?
UInt32
{
self
.
moveOnServer
(
uidValidity
:
uidValidity
,
mails
:
mails
,
fromPath
:
fromPath
,
toPath
:
toPath
,
completionHandler
:
{
error
in
// 3. Move mail in core data
self
.
dataProvider
.
moveMails
(
with
:
mails
,
from
:
fromPath
,
to
:
toPath
)
})
}
})
}
/* TODO
func move(mails: [MailRecord], from: String, to: String, folderCreated: Bool = false) {
guard IMAPSession != nil else {
return
}
let uids = MCOIndexSet()
if !DataHandler.handler.existsFolder(with: to) && !folderCreated {
let op = IMAPSession?.createFolderOperation(to)
op?.start({[unowned self] error in
guard error == nil else {
let conError = MailServerConnectionError.findErrorCode(error: error!)
self.errorhandling(error: conError, originalCall: {self.move(mails: mails, from: from, to: to)}, completionCallback: nil)
return
}
self.move(mails: mails, from: from, to: to, folderCreated: true)
})
} else {
let folderstatusFrom = IMAPSession?.folderStatusOperation(from)
folderstatusFrom?.start {[unowned self] (error, status) -> Void in
guard error == nil else {
let conerror = MailServerConnectionError.findErrorCode(error: error!)
self.errorhandling(error: conerror, originalCall: {self.move(mails: mails, from: from, to: to)}, completionCallback: nil)
return
}
if let statusFrom = status {
let uidValidity = statusFrom.uidValidity
let f = DataHandler.handler.findFolder(with: from)
if uidValidity == f.uidvalidity {
for mail in mails {
if mail.uidvalidity == uidValidity {
uids.add(mail.uid)
mail.folder.removeFromMails(mail)
if let record = mail.record {
record.removeFromPersistentMails(mail)
if record.mailsInFolder(folder: f).count == 0 {
f.removeFromKeyRecords(record)
}
}
DataHandler.handler.delete(mail: mail)
}
}
let op = self.IMAPSession?.moveMessagesOperation(withFolder: from, uids: uids, destFolder: to)
op?.start {[unowned self]
(err, vanished) -> Void in
guard err == nil else {
let conerror = MailServerConnectionError.findErrorCode(error: err!)
self.errorhandling(error: conerror, originalCall: {self.move(mails: mails, from: from, to: to)}, completionCallback: { err in
guard err != nil else {
return
}
let op = self.IMAPSession?.copyMessagesOperation(withFolder: from, uids: uids, destFolder: to)
op?.start({[unowned self] error, _ in
guard error == nil else {
return
}
uids.enumerate({uid in
self.setFlag(uid, flags: MCOMessageFlag.deleted, folder: from)
})
})
})
return
}
}
} else {
f.uidvalidity = uidValidity
}
}
}
}
}
*/
func
allFolders
(
_
completion
:
@escaping
(
Error
?)
->
Void
)
{
guard
IMAPSession
!=
nil
else
{
completion
(
MailServerConnectionError
.
NoData
)
...
...
@@ -536,7 +557,7 @@
if
let
folders
=
array
{
var
properities
=
[
FolderProperties
]()
for
folder
in
folders
{
let
property
=
FolderProperties
(
delimiter
:
String
(
Character
(
UnicodeScalar
(
UInt8
(
folder
.
delimiter
)))),
uidValidity
:
nil
,
lastUpdate
:
nil
,
maxUID
:
nil
,
minUID
:
nil
,
path
:
folder
.
path
,
parent
:
nil
,
children
:
nil
)
let
property
=
FolderProperties
(
delimiter
:
String
(
Character
(
UnicodeScalar
(
UInt8
(
folder
.
delimiter
)))),
uidValidity
:
nil
,
lastUpdate
:
nil
,
maxUID
:
nil
,
minUID
:
nil
,
path
:
folder
.
path
,
parent
:
nil
,
children
:
nil
,
flags
:
Int16
(
folder
.
flags
.
rawValue
)
)
properities
.
append
(
property
)
}
self
.
dataProvider
.
importNewData
(
from
:
properities
,
completionHandler
:
completion
)
...
...
enzevalos_iphone/New Group/Mailbot.swift
View file @
b9a45c3e
...
...
@@ -93,6 +93,7 @@ class Mailbot {
let
mail
=
MailProperties
(
messageID
:
UUID
()
.
uuidString
,
uid
:
0
,
subject
:
subject
,
date
:
Date
(),
flags
:
0
,
from
:
sender
,
...
...
@@ -106,7 +107,7 @@ class Mailbot {
maxUID
:
nil
,
minUID
:
nil
,
path
:
UserManager
.
backendInboxFolderPath
,
parent
:
nil
,
children
:
nil
),
parent
:
nil
,
children
:
nil
,
flags
:
0
),
body
:
body
,
attachments
:
[],
signatureState
:
SignatureState
.
ValidSignature
.
rawValue
,
...
...
enzevalos_iphone/OutgoingMail.swift
View file @
b9a45c3e
...
...
@@ -9,7 +9,7 @@
import
Foundation
class
OutgoingMail
{
static
var
OutgoingFolder
=
FolderProperties
(
delimiter
:
nil
,
uidValidity
:
nil
,
lastUpdate
:
nil
,
maxUID
:
nil
,
minUID
:
nil
,
path
:
"OutgoingMails"
,
parent
:
nil
,
children
:
nil
)
static
var
OutgoingFolder
=
FolderProperties
(
delimiter
:
nil
,
uidValidity
:
nil
,
lastUpdate
:
nil
,
maxUID
:
nil
,
minUID
:
nil
,
path
:
"OutgoingMails"
,
parent
:
nil
,
children
:
nil
,
flags
:
Int16
(
MCOIMAPFolderFlag
.
sentMail
.
rawValue
)
)
private
var
encAddresses
:
[
MCOAddress
]
=
[]
var
encReceivers
:
[
MCOAddress
]
{
...
...
@@ -162,9 +162,9 @@ class OutgoingMail {
let
to
=
self
.
toAddresses
.
map
({
AddressProperties
(
email
:
$0
.
mailbox
,
name
:
$0
.
displayName
)})
let
sigState
=
self
.
cryptoObject
?
.
signatureState
.
rawValue
??
SignatureState
.
NoSignature
.
rawValue
let
encState
=
self
.
cryptoObject
?
.
encryptionState
.
rawValue
??
EncryptionState
.
NoEncryption
.
rawValue
let
uuid
=
UUID
()
let
from
=
AddressProperties
(
email
:
self
.
sender
.
mailbox
,
name
:
self
.
sender
.
displayName
)
let
m
=
MailProperties
(
messageID
:
UUID
()
.
uuidString
,
subject
:
subject
,
date
:
Date
(),
flags
:
0
,
from
:
from
,
to
:
to
,
cc
:
cc
,
bcc
:
bcc
,
folder
:
OutgoingMail
.
OutgoingFolder
,
body
:
body
,
attachments
:
attachmentProperties
,
signatureState
:
sigState
,
encryptionState
:
encState
,
signatureKey
:
nil
,
decryptionKey
:
nil
,
autocryptHeaderKey
:
[],
attachedPublicKeys
:
[],
attachedSecretKeys
:
[])
let
m
=
MailProperties
(
messageID
:
uuid
.
uuidString
,
uid
:
UInt64
(
arc4random
()),
subject
:
subject
,
date
:
Date
(),
flags
:
0
,
from
:
from
,
to
:
to
,
cc
:
cc
,
bcc
:
bcc
,
folder
:
OutgoingMail
.
OutgoingFolder
,
body
:
body
,
attachments
:
attachmentProperties
,
signatureState
:
sigState
,
encryptionState
:
encState
,
signatureKey
:
nil
,
decryptionKey
:
nil
,
autocryptHeaderKey
:
[],
attachedPublicKeys
:
[],
attachedSecretKeys
:
[])
LetterboxModel
.
instance
.
dataProvider
.
importNewData
(
from
:
[
m
],
completionHandler
:
{
_
in
})
// TODO Fix crypto stuff (keys etc.)
}
...
...
@@ -190,7 +190,7 @@ class OutgoingMail {
func
send
(
informUser
:
Bool
=
false
)
{
self
.
informUser
=
informUser
if
let
mail
=
mail
{
LetterboxModel
.
instance
.
dataProvider
.
deleteMail
(
mail
:
mail
)
mail
.
delete
(
)
}
LetterboxModel
.
instance
.
mailHandler
.
sendSMTP
(
mail
:
self
,
callback
:
{
error
in
if
error
!=
nil
{
...
...
enzevalos_iphone/SwiftUI/Compose/ComposeHeaderView.swift
View file @
b9a45c3e
...
...
@@ -54,53 +54,50 @@ struct ComposeViewHeader: View {
.
disabled
(
model
.
recipientsModel
.
hasNoRecipients
)
}
// Encryption toggle
Toggle
(
""
,
isOn
:
$
model
.
encryptionOn
)
.
toggleStyle
(
EncryptionToggleStyle
())
.
labelsHidden
()
// Encryption button
encryptionButton
}
}
/// Custom styling for the encryption toggle in ComposeViewHeader.
struct
EncryptionToggleStyle
:
ToggleStyle
{
func
makeBody
(
configuration
:
Configuration
)
->
some
View
{
Button
{
configuration
.
isOn
.
toggle
()
}
label
:
{
// Separate labels required for desired scaling transition between states
if
configuration
.
isOn
{
encryptedButtonLabel
}
else
{
unencryptedButtonLabel
}
/// Encryption state button view
private
var
encryptionButton
:
some
View
{
Button
{
model
.
toogleEncryption
()
}
label
:
{
// Separate labels required for desired scaling transition between states
if
model
.
encryptionOn
{
encryptedButtonLabel
}
else
{
unencryptedButtonLabel
}
.
frame
(
width
:
40
,
height
:
40
)
}
/// Label style for encryption button when encryption is activated.
private
var
encryptedButtonLabel
:
some
View
{
ZStack
{
Circle
()
.
stroke
(
Color
.
blue
,
lineWidth
:
2
)
Image
(
systemName
:
"lock.fill"
)
.
font
(
Font
.
system
(
size
:
24
,
weight
:
Font
.
Weight
.
light
))
.
foregroundColor
(
.
blue
)
}
.
transition
(
AnyTransition
.
opacity
.
combined
(
with
:
.
scal
e
)
)
.
frame
(
width
:
40
,
height
:
40
)
}
/// Label style for encryption button when encryption is activated.
private
var
encryptedButtonLabel
:
some
View
{
ZStack
{
Circle
()
.
stroke
(
Color
.
blue
,
lineWidth
:
2
)
Image
(
systemName
:
"lock.fill"
)
.
font
(
Font
.
system
(
size
:
24
,
weight
:
Font
.
Weight
.
light
))
.
foregroundColor
(
.
blu
e
)
}
/// Label style for encryption button when encryption is deactivated.
private
var
unencryptedButtonLabel
:
some
View
{
ZStack
{
Circle
()
.
fill
(
Color
(
UIColor
.
tertiaryLabel
))
Image
(
systemName
:
"lock.slash.fill"
)
.
font
(
Font
.
system
(
size
:
24
,
weight
:
Font
.
Weight
.
light
))
.
foregroundColor
(
.
white
)
}
.
transition
(
AnyTransition
.
opacity
.
combined
(
with
:
.
scal
e
)
)
.
transition
(
AnyTransition
.
opacity
.
combined
(
with
:
.
scale
))
}
/// Label style for encryption button when encryption is deactivated.
private
var
unencryptedButtonLabel
:
some
View
{
ZStack
{
Circle
()
.
fill
(
Color
(
UIColor
.
tertiaryLabel
)
)
Image
(
systemName
:
"lock.slash.fill"
)
.
font
(
Font
.
system
(
size
:
24
,
weight
:
Font
.
Weight
.
light
))
.
foregroundColor
(
.
whit
e
)
}
.
transition
(
AnyTransition
.
opacity
.
combined
(
with
:
.
scale
))
}
}
enzevalos_iphone/SwiftUI/Compose/ComposeModel.swift
View file @
b9a45c3e
...
...
@@ -66,6 +66,15 @@ class ComposeModel: ObservableObject {
generateMail
()
.
send
()
}
/// Checks if encryption state can be toggled.
func
toogleEncryption
()
{
if
encryptionOn
{
encryptionOn
=
false
}
else
{
recipientsModel
.
checkEncryption
()
}
}
/// Adds email addresses to given RecipientFieldModel.
///
/// - Parameters:
...
...
@@ -75,6 +84,13 @@ class ComposeModel: ObservableObject {
for
address
in
addresses
{
model
.
addNewAddress
(
address
)
}
let
frc
=
PersistentDataProvider
.
dataProvider
.
generateFetchedAddresesWithKeyResultsController
(
addresses
:
addresses
)
if
let
records
=
frc
.
fetchedObjects
{
if
encryptionOn
&&
records
.
count
!=
addresses
.
count
{
encryptionOn
=
false
}
}
}
/// Generates OutgoingMail with given email contents.
...
...
enzevalos_iphone/SwiftUI/Compose/ComposeView.swift
View file @
b9a45c3e
...
...
@@ -206,7 +206,6 @@ struct RecipientField: View {
// and Bcc fields getting collapsed again despite the
// first recipient clearly getting rendered as a blue
// capsule in the ForEach loop above. 🤔🤔🤔
print
(
model
.
selectedContacts
.
count
)
}
.
frame
(
width
:
200
)
// TODO: Stretch dynamically over available horizontal space
.
autocapitalization
(
.
none
)
// .frame(maxWidth: .infinity) somehow doesn't work
...
...
enzevalos_iphone/SwiftUI/Compose/RecipientFieldModel.swift
View file @
b9a45c3e
...
...
@@ -82,6 +82,9 @@ class RecipientFieldModel: ObservableObject {
/// - Parameter _: AddressRecord that gets added to array of recipients.
func
selectContact
(
_
addressRecord
:
AddressRecord
)
{
selectedContacts
.
append
(
addressRecord
)
if
!
addressRecord
.
hasPublicKey
{
self
.
parentRecipientModel
?
.
parentComposeModel
?
.
encryptionOn
=
false
}
text
=
""
suggestions
=
[]
...
...
@@ -97,8 +100,12 @@ class RecipientFieldModel: ObservableObject {
///
/// - Parameter at: Index of contact to be removed from array of recipients.
func
deselectContact
(
at
index
:
Int
)
{
selectedContacts
.
remove
(
at
:
index
)
let
addr
=
selectedContacts
[
index
]
selectedContacts
.
remove
(
at
:
index
)
if
!
addr
.
hasPublicKey
{
parentRecipientModel
?
.
checkEncryption
()
}
// TODO: See TODO in selectContact.
parentRecipientModel
?
.
parentComposeModel
?
.
subject
+=
""
}
...
...
@@ -132,6 +139,9 @@ class RecipientFieldModel: ObservableObject {
if
let
addresses
=
frc
.
fetchedObjects
,
let
addr
=
addresses
.
first
{
self
.
selectedContacts
.
append
(
addr
)
if
!
addr
.
hasPublicKey
{
self
.
parentRecipientModel
?
.
parentComposeModel
?
.
encryptionOn
=
false
}
}
}
}
...
...
enzevalos_iphone/SwiftUI/Compose/RecipientsModel.swift
View file @
b9a45c3e
...
...
@@ -44,9 +44,7 @@ class RecipientsModel: ObservableObject {
/// Used to show or hide Bcc field
var
isEditingCcOrBcc
:
Bool
=
false
{
didSet
{
print
(
"isEditingCcOrBcc:
\(
isEditingCcOrBcc
)
"
)
updateShowBccField
()
print
(
"showBccField:
\(
showBccField
)
"
)
}
}
...
...
@@ -91,6 +89,26 @@ class RecipientsModel: ObservableObject {
||
!
bccModel
.
selectedContacts
.
isEmpty
ccModel
.
type
=
showBccField
?
.
cc
:
.
ccBcc
}
/// Turnes encryption on if all recipients have a key.
func
checkEncryption
()
{
for
addr
in
toModel
.
selectedContacts
{
if
!
addr
.
hasPublicKey
{
return
}
}
for
addr
in
ccModel
.
selectedContacts
{
if
!
addr
.
hasPublicKey
{
return
}
}
for
addr
in
bccModel
.
selectedContacts
{
if
!
addr
.
hasPublicKey
{
return
}
}
parentComposeModel
?
.
encryptionOn
=
true
}
}
/// Type of recipient field (to, cc, bcc).
...
...
enzevalos_iphone/SwiftUI/Contact/ContactMailListView.swift
View file @
b9a45c3e
...
...
@@ -37,7 +37,7 @@ struct ContactMailListView: View {
ForEach
(
0
..<
min
(
3
,
filteredEmails
.
count
))
{
record
in
NavigationLink
(
destination
:
ReadMainView
(
model
:
ReadModel
(
mail
:
filteredEmails
[
record
])))
{
MailRowView
(
mail
:
filteredEmails
[
record
]
,
activateOnTap
:
false
)
Simple
MailRowView
(
mail
:
filteredEmails
[
record
])
}
if
record
<
min
(
2
,
filteredEmails
.
count
-
1
)
{
Divider
()
...
...
enzevalos_iphone/SwiftUI/Contact/ContactView.swift
View file @
b9a45c3e
...
...
@@ -30,7 +30,6 @@ struct ContactView <C: DisplayContact>: View {
VStack
{
HStack
{
avatar
VStack
(
alignment
:
.
leading
)
{
contactName
.
padding
(
.
bottom
)
knownSince
...
...
@@ -144,7 +143,7 @@ struct ContactView <C: DisplayContact>: View {
}
label
:
{
Text
(
"
\(
eachAddress
)
"
)
.
fontWeight
(
.
light
)
.
font
(
.
title2
)
.
font
(
.
body
)
.
foregroundColor
(
.
blue
)
.
truncationMode
(
.
middle
)
.
frame
(
maxWidth
:
.
infinity
,
...
...
@@ -157,32 +156,11 @@ struct ContactView <C: DisplayContact>: View {
// This row shows the security rating and a button do display the keys
HStack
{
rating
Button
{
withAnimation
{