Commit b631329b authored by wieseoli's avatar wieseoli

Merge branch '155-ui-for-gamifcation-stats' into 'dev'

Create badge case screen

See merge request !56
parents bbd7c77b 9c22f8a5
......@@ -195,6 +195,8 @@
8428A8711F436A1E007649A5 /* GamificationStatusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8428A86D1F436A1E007649A5 /* GamificationStatusViewController.swift */; };
8428A8831F436AC9007649A5 /* GamificationDataUnitTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8428A8561F4369EA007649A5 /* GamificationDataUnitTest.swift */; };
8428A8841F436ACC007649A5 /* GamificationElements.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8428A8541F4369CF007649A5 /* GamificationElements.xcassets */; };
971D404A2428C87E002FCD31 /* BadgeCaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 971D40492428C87E002FCD31 /* BadgeCaseView.swift */; };
97BDE0432429188500B0BF03 /* BadgeProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97BDE0422429188500B0BF03 /* BadgeProgressView.swift */; };
988C9C5D240D507A006213F0 /* UrlStringExtensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 988C9C5C240D507A006213F0 /* UrlStringExtensionTests.swift */; };
A102AA8A1EDDB4F40024B457 /* videoOnboarding2.m4v in Resources */ = {isa = PBXBuildFile; fileRef = A102AA891EDDB4E80024B457 /* videoOnboarding2.m4v */; };
A1083A541E8BFEA6003666B7 /* Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1083A531E8BFEA6003666B7 /* Onboarding.swift */; };
......@@ -624,8 +626,10 @@
8B87EFB6CEAA31452F744015 /* Pods-enzevalos_iphoneUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-enzevalos_iphoneUITests.release.xcconfig"; path = "../enzevalos_iphone_workspace/Pods/Target Support Files/Pods-enzevalos_iphoneUITests/Pods-enzevalos_iphoneUITests.release.xcconfig"; sourceTree = "<group>"; };
91B6C9020C660BEA78FAEF28 /* Pods-enzevalos_iphone.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-enzevalos_iphone.debug.xcconfig"; path = "../enzevalos_iphone_workspace/Pods/Target Support Files/Pods-enzevalos_iphone/Pods-enzevalos_iphone.debug.xcconfig"; sourceTree = "<group>"; };
94EE54279AB591E0CAB8EFD8 /* Pods_enzevalos_iphone.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_enzevalos_iphone.framework; sourceTree = BUILT_PRODUCTS_DIR; };
971D40492428C87E002FCD31 /* BadgeCaseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeCaseView.swift; sourceTree = "<group>"; };
9771AA8B241161190023A096 /* MailAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MailAccount.swift; sourceTree = "<group>"; };
97AACD2324178C230078A68E /* AuthenticationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationModel.swift; sourceTree = "<group>"; };
97BDE0422429188500B0BF03 /* BadgeProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeProgressView.swift; sourceTree = "<group>"; };
97C5279E241A9F7B0030BBC9 /* AuthenticationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationTests.swift; sourceTree = "<group>"; };
97C527A0241AA4090030BBC9 /* GeneratedMocks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GeneratedMocks.swift; path = enzevalos_iphoneTests/GeneratedMocks.swift; sourceTree = SOURCE_ROOT; };
988C9C5C240D507A006213F0 /* UrlStringExtensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UrlStringExtensionTests.swift; sourceTree = "<group>"; };
......@@ -1315,6 +1319,15 @@
name = Data;
sourceTree = "<group>";
};
971D40482428C852002FCD31 /* gamification_2 */ = {
isa = PBXGroup;
children = (
971D40492428C87E002FCD31 /* BadgeCaseView.swift */,
97BDE0422429188500B0BF03 /* BadgeProgressView.swift */,
);
name = gamification_2;
sourceTree = "<group>";
};
97C5279D241A9F690030BBC9 /* authentication */ = {
isa = PBXGroup;
children = (
......@@ -1395,6 +1408,7 @@
children = (
0EFEF0932417C08B00BB2FF7 /* C Helpers */,
6789425D2430C38800C746D1 /* Phishing */,
971D40482428C852002FCD31 /* gamification_2 */,
47EABF05241A9C7000774A93 /* Authentication */,
476406872416B54D00C7D426 /* SwiftUI */,
476403FA2413F95300C7D426 /* OpenSSL */,
......@@ -2111,6 +2125,7 @@
A1AEBA5921E808CB00C84E59 /* IntroYesNoViewController.swift in Sources */,
A1EB05941D956931008659C1 /* InboxCellDelegator.swift in Sources */,
8428A85D1F436A05007649A5 /* Badges.swift in Sources */,
971D404A2428C87E002FCD31 /* BadgeCaseView.swift in Sources */,
8428A8651F436A11007649A5 /* BadgeCaseCollectionViewCell.swift in Sources */,
472F39811E1E5347009260FB /* Mail_Address+CoreDataClass.swift in Sources */,
A1EB05821D95685B008659C1 /* CollectionDataDelegate.swift in Sources */,
......@@ -2136,6 +2151,7 @@
476406972416B54D00C7D426 /* InboxCoordinator.swift in Sources */,
0EF148082422572500B3C198 /* general-helpers.c in Sources */,
F113C3851F30D06800E7F1D6 /* QRScannerView.swift in Sources */,
97BDE0432429188500B0BF03 /* BadgeProgressView.swift in Sources */,
477670C6228454F700043604 /* ButtonCell.swift in Sources */,
F18B44601E704C550080C041 /* ReplaceSegue.swift in Sources */,
8428A8661F436A11007649A5 /* ArrowTableViewCell.swift in Sources */,
......
......@@ -130,6 +130,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
});
}
}
func showBadgeCase() {
guard let vc = self.window?.rootViewController as? UINavigationController else {
fatalError("No rootViewController!")
}
let nextVC = UIHostingController(rootView: BadgeCaseView())
vc.navigationBar.isHidden = true
vc.pushViewController(nextVC, animated: true)
}
// Option removed from Settings app, but this might still be usefull in the future
func resetApp() {
......
//
// BadgeCaseView.swift
// enzevalos_iphone
//
// Created by Sezzart on 23.03.20.
// Copyright © 2020 fu-berlin. All rights reserved.
//
import SwiftUI
struct BadgeCaseView: View {
init() {
UITableView.appearance().separatorStyle = .none
}
let badges: [Badge] = GamificationData.sharedInstance.badges.map { Badge(type: $0.type, description: $0.displayName, imageOn: $0.onName, imageOff: $0.offName, isActive: $0.isAchieved()) }
var body: some View {
NavigationView {
VStack {
Divider()
Spacer()
List {
ForEach(badges) { badge in
NavigationLink(destination: BadgeProgressView(badge: badge)) {
BadgeItem(badgeType: badge.type, badgeImageSrcOn: badge.imageOn, badgeImageSrcOff: badge.imageOff, badgeTitle: badge.description, isActive: badge.isActive)
}
}
}
}.navigationBarTitle(Text(NSLocalizedString("Gamification.Overview.HeaderTitle", comment:"Badge Case Navigation Title" )), displayMode: .inline).navigationBarItems(leading: Button(action: goBack, label: {
Text(NSLocalizedString("Back", comment: ""))
}))
}
}
func goBack() {
if let coord = AppDelegate.getAppDelegate().inboxCoordinator {
coord.goBack()
}
}
}
struct Badge: Identifiable {
var id = UUID()
var type: BadgeType
var description: String
var imageOn: String
var imageOff: String
var isActive: Bool
}
struct BadgeItem: View {
let badgeType: BadgeType
let badgeImageSrcOn: String
let badgeImageSrcOff: String
let badgeTitle: String
var isActive: Bool
init(badgeType: BadgeType, badgeImageSrcOn: String, badgeImageSrcOff: String, badgeTitle: String, isActive: Bool = false) {
self.badgeType = badgeType
self.badgeImageSrcOn = badgeImageSrcOn
self.badgeImageSrcOff = badgeImageSrcOff
self.badgeTitle = badgeTitle
self.isActive = isActive
}
var body: some View {
HStack {
Image(isActive ? badgeImageSrcOn : badgeImageSrcOff)
.resizable()
.scaledToFit()
.frame(width: 40,height: 40)
.padding(10)
Text(self.badgeTitle)
}
}
}
struct BadgeCaseView_Previews: PreviewProvider {
static var previews: some View {
BadgeCaseView()
}
}
//
// BadgeProgressView.swift
// enzevalos_iphone
//
// Created by Sezzart on 23.03.20.
// Copyright © 2020 fu-berlin. All rights reserved.
//
import SwiftUI
struct BadgeProgressView: View {
let badge: Badge
var body: some View {
VStack {
titleBar
Divider()
List {
ForEach(GamificationData.sharedInstance.subBadgesforBadge(badge: badge.type).map { Badge(type: $0.type, description: $0.displayName, imageOn: $0.onName, imageOff: $0.offName, isActive: $0.isAchieved()) }) { subBadge in
Quest(isQuestCompleted: subBadge.isActive, description: subBadge.description, imageOn: subBadge.imageOn, imageOff: subBadge.imageOff)
}
}
}
}
private var titleBar: some View {
HStack{
Image(badge.imageOn)
.resizable()
.scaledToFit()
.frame(width: 50,height: 50)
.padding(5)
Text(badge.description)
Spacer()
}
}
}
struct Quest: View {
let isQuestCompleted: Bool
let description: String
let imageOn: String
let imageOff: String
init(isQuestCompleted: Bool, description: String, imageOn: String, imageOff: String) {
self.isQuestCompleted = isQuestCompleted
self.description = description
self.imageOn = imageOn
self.imageOff = imageOff
}
var body: some View {
HStack {
Image(isQuestCompleted ? imageOn : imageOff)
.resizable()
.scaledToFit()
.frame(width: 40,height: 40)
.padding(10)
Text(description)
}
}
}
struct BadgeProgressView_Previews: PreviewProvider {
static var previews: some View {
BadgeProgressView(badge: Badge(type: .MailMaster, description: NSLocalizedString("Mailmaster", comment:"Mailmaster badge" ), imageOn: "verschluesseltOn", imageOff: "verschluesseltOff", isActive: true))
}
}
......@@ -35,6 +35,7 @@ enum BadgeType: Int {
case onBoarding
case inviteAFriend
case Ambassador
case friendlyKeyMaster
case MailMaster
case MailMaster1
......@@ -51,6 +52,11 @@ enum BadgeType: Int {
case SecureMailMaster100
case SecureMailMaster1000
case None // for SubBadge
case FriendlyKeyMaster
case FriendlyKeyMaster10
case FriendlyKeyMaster50
case FriendlyKeyMaster100
}
/**
......@@ -72,6 +78,10 @@ enum Achievment {
case SecureMails1000
case SecureSend
case SecureReceived
case FriendlyKeyMaster1
case FriendlyKeyMaster10
case FriendlyKeyMaster50
case FriendlyKeyMaster100
}
/**
......
This diff is collapsed.
......@@ -86,6 +86,7 @@ class ContactViewController: UIViewController {
if let row = tableView.indexPathForSelectedRow {
tableView.deselectRow(at: row, animated: false)
}
navigationController?.navigationBar.isHidden = false
}
@objc func feedback() {
......@@ -536,7 +537,7 @@ extension ContactViewController: UITableViewDataSource {
let badgeCell = tableView.dequeueReusableCell(withIdentifier: "BadgeCaseCell", for: indexPath)
badgeCell.detailTextLabel?.text = NSLocalizedString("YourBadges", comment: "")
if StudySettings.hideBadges {
badgeCell.isHidden = true
badgeCell.isHidden = false
}
return badgeCell
case 6 where isUser:
......@@ -646,6 +647,13 @@ extension ContactViewController: UITableViewDelegate {
UIPasteboard.general.string = keyRecord!.ezContact.getMailAddresses()[indexPath.row].mailAddress
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let BADGE_CASE_CELL_ROW = 5
if indexPath.section == BADGE_CASE_CELL_ROW {
AppDelegate.getAppDelegate().showBadgeCase()
}
}
}
extension ContactViewController: UINavigationControllerDelegate {
......
......@@ -43,7 +43,8 @@ class GamificationData: NSObject {
Badges.init(type: .SecureMailMaster , pictureOff: "verschluesseltOff", pictureOn: "verschluesseltOn", segue: .LinearBadge, displayName: NSLocalizedString("Secure Mailmaster", comment:"Secure Mailmaster badge" )),
Badges.init(type: .onBoarding, pictureOff: "onboardingOff", pictureOn: "onboardingOn", segue: .LinearBadge, displayName: NSLocalizedString("Onboarded", comment:"Onboarded" )),
Badges.init(type: .inviteAFriend, pictureOff: "invitefriendOff", pictureOn: "invitefriendOn", segue: .inviteFriend, displayName: NSLocalizedString("Invite a friend", comment: "Invite a friend" )),
Badges.init(type: .Ambassador, pictureOff: "ambassadorOff", pictureOn: "ambassadorOn", segue: .inviteFriend, displayName: NSLocalizedString("Ambassador", comment:"Ambassador" ))
Badges.init(type: .Ambassador, pictureOff: "ambassadorOff", pictureOn: "ambassadorOn", segue: .inviteFriend, displayName: NSLocalizedString("Ambassador", comment:"Ambassador" )),
Badges.init(type: .friendlyKeyMaster, pictureOff: "keymasterOff", pictureOn: "keymasterOn", segue: .LinearBadge, displayName: NSLocalizedString("Friendly Key Master", comment: "Friendly Key Master" ))
]
......@@ -89,6 +90,14 @@ class GamificationData: NSObject {
Badges.init(type: .SecureMailMaster100 , pictureOff: "verschluesseltOff", pictureOn: "verschluesseltOn", displayName: NSLocalizedString("100 secure Mails Send/Received", comment:"SecureMailMaster Subbadge" ), achievmentsNeeded: [.SecureMails100]),
Badges.init(type: .SecureMailMaster1000 , pictureOff: "verschluesseltOff", pictureOn: "verschluesseltOn", displayName: NSLocalizedString("1000 secure Mails Send/Received", comment:"SecureMailMaster Subbadge" ), achievmentsNeeded: [.SecureMails1000])
]
case .friendlyKeyMaster:
return [
Badges.init(type: .FriendlyKeyMaster , pictureOff: "keymasterOff", pictureOn: "keymasterOn", displayName: NSLocalizedString("One friends public key stored", comment:"FriendlyKeyMaster Subbadge" ), achievmentsNeeded: [.FriendlyKeyMaster1 ]),
Badges.init(type: .FriendlyKeyMaster10 , pictureOff: "keymasterOff", pictureOn: "keymasterOn", displayName: NSLocalizedString("10 friends public keys stored", comment:"FriendlyKeyMaster Subbadge" ), achievmentsNeeded: [.FriendlyKeyMaster10 ]),
Badges.init(type: .FriendlyKeyMaster50 , pictureOff: "keymasterOff", pictureOn: "keymasterOn", displayName: NSLocalizedString("50 friends public keys stored", comment:"FriendlyKeyMaster Subbadge" ), achievmentsNeeded: [.FriendlyKeyMaster50 ]),
Badges.init(type: .FriendlyKeyMaster100 , pictureOff: "keymasterOff", pictureOn: "keymasterOn", displayName: NSLocalizedString("100 friends public keys stored", comment:"FriendlyKeyMaster Subbadge" ), achievmentsNeeded: [.FriendlyKeyMaster100])
]
default:
return [Badges]()
......@@ -286,6 +295,14 @@ class GamificationData: NSObject {
return secureMailsSend > 0
case .SecureReceived:
return secureMailsReceived > 0
case .FriendlyKeyMaster1:
return secureContactsCount > 0
case .FriendlyKeyMaster10:
return secureContactsCount > 9
case .FriendlyKeyMaster50:
return secureContactsCount > 49
case .FriendlyKeyMaster100:
return secureContactsCount > 99
// default: return false
}
}
......
......@@ -25,7 +25,7 @@ struct Inbox: View {
var body: some View {
VStack{
SearchView(searchText: $searchText, searchField: $searchField, searchNow: $searchNow)
.padding(6)
.padding(6)
// Mails
mailList
// Toolbar
......@@ -46,10 +46,10 @@ struct Inbox: View {
List (self.keyrecords.filter(filterKeyRecord), id: \.self){
record in
KeyRecordRow(keyrecord: record, coord: self.coord).environment(\.managedObjectContext, self.managedObjectContext)
}
.resignKeyboardOnDragGesture() // hide keyboard when dragging
}
.resignKeyboardOnDragGesture() // hide keyboard when dragging
}
private var folderButton: some View {
Button(action: self.coord.pushFoldersView, label: {
Text(NSLocalizedString("Folders", comment: "Folder"))
......@@ -74,7 +74,7 @@ struct Inbox: View {
var text = NSLocalizedString("Updating", comment: "updating...")
if !updating {
if let last = Folder.inbox.lastUpdate {
let dateFormatter = DateFormatter()
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale.current
dateFormatter.timeStyle = .medium
let dateString = dateFormatter.string(from: last)
......@@ -86,56 +86,56 @@ struct Inbox: View {
}
return Button(action: updateMails, label: {Text(text)
.font(.callout)
})
}
var userRecord: KeyRecord {
get {
let keyID = UserManager.loadUserValue(Attribute.prefSecretKeyID) as? String
let addr = UserManager.loadUserValue(Attribute.userAddr) as! String
return DataHandler.handler.getKeyRecord(addr: addr, keyID: keyID)
}
}
func updateMails() {
guard !updating else {
return
}
AppDelegate.getAppDelegate().mailHandler.updateFolder(folder: Folder.inbox, completionCallback: {_ in
self.updating = false
})
updating = true
}
func filterKeyRecord(keyRecord: KeyRecord) -> Bool {
let searchType = SearchType.findType(i: searchField)
if self.searchText.isEmpty || self.searchText == NSLocalizedString("Searchbar.Title", comment: "Search") {
return true
}
let query = self.searchText.lowercased()
if (searchType == .All || searchType == .Sender) && containsSearchTerms(content: keyRecord.name, searchText: query){
return true
}
else if (searchType == .All || searchType == .Sender) && keyRecord.addresses.filter({containsSearchTerms(content: $0.mailAddress, searchText: query)}).count > 0 {
return true
}
else if (searchType == .All || searchType == .Subject) && keyRecord.mails.filter({containsSearchTerms(content: $0.subject, searchText: query)}).count > 0 {
return true
}
else if (searchType == .All || searchType == .Body) && keyRecord.mails.filter({containsSearchTerms(content: $0.body, searchText: query)}).count > 0 {
return true
}
return false
}
get {
let keyID = UserManager.loadUserValue(Attribute.prefSecretKeyID) as? String
let addr = UserManager.loadUserValue(Attribute.userAddr) as! String
return DataHandler.handler.getKeyRecord(addr: addr, keyID: keyID)
}
}
func updateMails() {
guard !updating else {
return
}
AppDelegate.getAppDelegate().mailHandler.updateFolder(folder: Folder.inbox, completionCallback: {_ in
self.updating = false
})
updating = true
}
func filterKeyRecord(keyRecord: KeyRecord) -> Bool {
let searchType = SearchType.findType(i: searchField)
if self.searchText.isEmpty || self.searchText == NSLocalizedString("Searchbar.Title", comment: "Search") {
return true
}
let query = self.searchText.lowercased()
if (searchType == .All || searchType == .Sender) && containsSearchTerms(content: keyRecord.name, searchText: query){
return true
}
else if (searchType == .All || searchType == .Sender) && keyRecord.addresses.filter({containsSearchTerms(content: $0.mailAddress, searchText: query)}).count > 0 {
return true
}
else if (searchType == .All || searchType == .Subject) && keyRecord.mails.filter({containsSearchTerms(content: $0.subject, searchText: query)}).count > 0 {
return true
}
else if (searchType == .All || searchType == .Body) && keyRecord.mails.filter({containsSearchTerms(content: $0.body, searchText: query)}).count > 0 {
return true
}
return false
}
}
/*
struct Inbox_Previews: PreviewProvider {
static var previews: some View {
Inbox()
}
}
struct Inbox_Previews: PreviewProvider {
static var previews: some View {
Inbox()
}
}
*/
......@@ -22,6 +22,10 @@ class InboxCoordinator {
mainStoryboard = UIStoryboard(name: self.mainStoryboardName, bundle: nil)
}
func goBack() {
root.popViewController(animated: true)
}
func pushInbox(){
try? AppDelegate.getAppDelegate().mailHandler.startIMAPIdleIfSupported()
AppDelegate.getAppDelegate().mailHandler.updateFolder(folder: Folder.inbox, completionCallback: {_ in
......@@ -31,9 +35,7 @@ class InboxCoordinator {
if let vc = inbox {
if root.viewControllers.contains(vc) {
while root.topViewController != vc {
root.popViewController(animated: true)
}
root.popToViewController(vc, animated: false)
} else {
root.pushViewController(vc, animated: true)
}
......
......@@ -356,3 +356,4 @@
"Feedback.Name" = "Feedback";
"MailView.MoreMails" = "Mehr Mails sehen";
"Searchbar.Title" = "Suchen";
"Gamification.Overview.HeaderTitle" = "Abzeichen";
......@@ -330,3 +330,5 @@
"Feedback.Name" = "Feedback";
"MailView.MoreMails" = "See more mails";
"Searchbar.Title" = "Search";
"Gamification.Overview.HeaderTitle" = "Badge Case";
// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationModel.swift at 2020-04-03 07:21:06 +0000
// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationModel.swift at 2020-04-03 09:04:12 +0000
//
// AuthenticationModel.swift
......@@ -653,7 +653,7 @@ import Foundation
}
// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationViewModel.swift at 2020-04-03 07:21:06 +0000
// MARK: - Mocks generated from file: enzevalos_iphone/AuthenticationViewModel.swift at 2020-04-03 09:04:12 +0000
//
// AuthenticationViewModel.swift
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment