Skip to content
Snippets Groups Projects
Commit 4a715c64 authored by lazarog98's avatar lazarog98
Browse files

Merge branch '238-improve-searching' into 'dev'

Resolve "Improve searching"

See merge request !27
parents cc5bbf8e 54c0490a
Branches
Tags
3 merge requests!58Onboarding screens swift ui merge dev,!55WIP: Resolve "UI for gamifcation & stats",!27Resolve "Improve searching"
......@@ -41,3 +41,5 @@ DerivedData
DerivedData.noindex
*.xcuserstate
*.swp
private
*.zip
......@@ -13,6 +13,7 @@
0E1C457D24055F87006D104A /* signencinlineK9.eml in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C457924055F87006D104A /* signencinlineK9.eml */; };
0E1C458024055FB7006D104A /* Alice.v3.pubsec.asc in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C457E24055FB7006D104A /* Alice.v3.pubsec.asc */; };
0E1C458124055FB7006D104A /* Alice.v3.pub.asc in Resources */ = {isa = PBXBuildFile; fileRef = 0E1C457F24055FB7006D104A /* Alice.v3.pub.asc */; };
0E6551A72406A42300DE30FC /* SearchHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E6551A62406A42300DE30FC /* SearchHelper.swift */; };
3E6B07DE2011246500E49609 /* invitationText.html in Resources */ = {isa = PBXBuildFile; fileRef = 3E6B07DD2011246500E49609 /* invitationText.html */; };
3EB4FA9F2012007C001D0625 /* DialogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3EB4FA9D2012007C001D0625 /* DialogViewController.swift */; };
3EB4FAA12012007C001D0625 /* Dialog.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3EB4FA9E2012007C001D0625 /* Dialog.storyboard */; };
......@@ -270,6 +271,7 @@
0E1C457924055F87006D104A /* signencinlineK9.eml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = signencinlineK9.eml; sourceTree = "<group>"; };
0E1C457E24055FB7006D104A /* Alice.v3.pubsec.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Alice.v3.pubsec.asc; sourceTree = "<group>"; };
0E1C457F24055FB7006D104A /* Alice.v3.pub.asc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Alice.v3.pub.asc; sourceTree = "<group>"; };
0E6551A62406A42300DE30FC /* SearchHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchHelper.swift; sourceTree = "<group>"; };
1D4A9E60565DECF52C011BC0 /* Pods-enzevalos_iphone-AdHoc.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-enzevalos_iphone-AdHoc.release.xcconfig"; path = "../enzevalos_iphone_workspace/Pods/Target Support Files/Pods-enzevalos_iphone-AdHoc/Pods-enzevalos_iphone-AdHoc.release.xcconfig"; sourceTree = "<group>"; };
3E6B07DD2011246500E49609 /* invitationText.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; name = invitationText.html; path = Invitation/invitationText.html; sourceTree = "<group>"; };
3E9708AD1FAC925D005825C9 /* enzevalos_iphone.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = enzevalos_iphone.entitlements; sourceTree = "<group>"; };
......@@ -1149,6 +1151,7 @@
A1EB05971D956947008659C1 /* InboxViewController.swift */,
F120607F1DA540FE00F6EF37 /* RefreshControlExtension.swift */,
A1F9923B1DA7DD2E0073BF1B /* InboxTableViewCell.xib */,
0E6551A62406A42300DE30FC /* SearchHelper.swift */,
);
name = inbox;
sourceTree = "<group>";
......@@ -1642,6 +1645,7 @@
472F39701E14F75C009260FB /* DataHandler.swift in Sources */,
A1C62E9A2018F716000E5273 /* OnboardingValueState.swift in Sources */,
A1EB05901D956923008659C1 /* ReadViewController.swift in Sources */,
0E6551A72406A42300DE30FC /* SearchHelper.swift in Sources */,
472F398E1E251B8D009260FB /* MailAddress.swift in Sources */,
A198D2292056B384004CC838 /* SendViewDelegate.swift in Sources */,
479011492289975D0057AB04 /* NoSecIconStyleKit.swift in Sources */,
......
This diff is collapsed.
......@@ -40,6 +40,11 @@ class InboxViewController: UITableViewController, InboxCellDelegator {
}
}
// how many seconds should the app wait before processing search bar input
private let searchDelay = 0.5
// holds the currently active search timer (if it exists) so it can be terminated if a new character is typed before the execution
private var searchBarTimer: Timer?
@IBOutlet weak var lastUpdateButton: UIBarButtonItem!
var lastUpdateLabel = UILabel(frame: CGRect.zero)
var lastUpdateText: String? {
......@@ -248,34 +253,60 @@ class InboxViewController: UITableViewController, InboxCellDelegator {
return searchController.isActive && !searchBarIsEmpty
}
func filterContentForSearchText(_ searchText: String, scope: Int = 0) {
var records = [KeyRecord]()
if scope == 0 || scope == 3 {
records += folder.records.filter({ (record: KeyRecord) -> Bool in
return record.name.lowercased().contains(searchText.lowercased())
})
/**
searches a given string with a delay so that the entire client doesn't lag if the inbox is very big
- parameters:
- searchText: srtring to look for
- scope: where to search (look at _filterContentForSearchText)
*/
func startSearch(searchText: String, scope: Int = 0) {
// check if a search has been scheduled already and stop it to prevent multiple searches
if let searchBarTimer: Timer = self.searchBarTimer {
searchBarTimer.invalidate()
}
if scope == 1 || scope == 3 {
records += folder.records.filter({ (record: KeyRecord) -> Bool in
let mails = record.inboxMails
return mails.filter({ (mail: PersistentMail) -> Bool in
mail.subject?.lowercased().contains(searchText.lowercased()) ?? false
}).count > 0
self.searchBarTimer = Timer.scheduledTimer(withTimeInterval: searchDelay, repeats: false, block: { _ in
self._filterContentForSearchText(searchText, scope: scope)
})
}
if scope == 2 || scope == 3 {
records += folder.records.filter({ (record: KeyRecord) -> Bool in
/**
Filters emails by a user input string and scope
- parameters:
- scope: 0 = contact name; 1 = subject; 2 = body; 3 = all
- searchText: the string we are looking for
*/
private func _filterContentForSearchText(_ searchText: String, scope: Int = 0) {
let records = folder.records.filter({ (record: KeyRecord) -> Bool in
if scope == 0
{
return containsSearchTerms(content: record.name, searchText: searchText)
}
let mails = record.inboxMails
return mails.filter({ (mail: PersistentMail) -> Bool in
// concatenate all strings that fall in our scope
var str = ""
if scope == 1 || scope == 3
{
str.append(contentsOf: mail.subject ?? "")
}
if scope == 2 || scope == 3
{
if let decryptedBody = mail.decryptedBody {
return decryptedBody.lowercased().contains(searchText.lowercased())
str.append(decryptedBody)
} else if !mail.isEncrypted {
return mail.body?.lowercased().contains(searchText.lowercased()) ?? false
str.append(contentsOf: mail.body ?? "")
}
return false
}
if scope == 3
{
str.append(contentsOf: record.name)
}
return containsSearchTerms(content: str, searchText: searchText)
}).count > 0
})
}
filteredRecords = records.unique.sorted()
tableView.reloadData()
......@@ -286,13 +317,13 @@ extension InboxViewController: UISearchResultsUpdating {
// https://www.raywenderlich.com/157864/uisearchcontroller-tutorial-getting-started
func updateSearchResults(for searchController: UISearchController) {
filterContentForSearchText(searchController.searchBar.text!, scope: searchController.searchBar.selectedScopeButtonIndex)
startSearch(searchText: searchController.searchBar.text!, scope: searchController.searchBar.selectedScopeButtonIndex)
}
}
extension InboxViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
filterContentForSearchText(searchBar.text!, scope: selectedScope)
startSearch(searchText: searchBar.text!, scope: selectedScope)
}
}
......
......@@ -69,6 +69,9 @@ class ListViewController: UITableViewController {
}
var loading = false
private let searchDelay = 0.5
private var searchTimer: Timer?
override func viewWillAppear(_ animated: Bool) {
tableView.reloadData()
}
......@@ -106,62 +109,52 @@ class ListViewController: UITableViewController {
print("===============|| ListViewController deinitialized ||===============")
}
func filterContentForSearchText(_ searchText: String, scope: Int = 0) {
filteredMails = contact!.mails.filter { mail in
var returnValue = false
switch scope {
case 0:
if let subject = mail.subject {
returnValue = subject.lowercased().contains(searchText.lowercased())
}
case 1:
if !returnValue && mail.decryptedBody != nil {
returnValue = mail.decryptedBody!.lowercased().contains(searchText.lowercased())
} else if !returnValue && mail.body != nil {
returnValue = mail.body!.lowercased().contains(searchText.lowercased())
}
case 2:
if !returnValue && mail.cc?.count > 0 {
if let result = mail.cc?.contains(where: { cc -> Bool in
if let mail = cc as? MailAddress {
return mail.mailAddress.contains(searchText.lowercased())
}
return false
}) {
returnValue = result
}
func startSearch(searchText: String, scope: Int = 0) {
// check if a search has been scheduled already and stop it to prevent multiple searches
if let searchBarTimer: Timer = self.searchTimer {
searchBarTimer.invalidate()
}
if !returnValue && mail.getReceivers().count > 1 {
returnValue = mail.getReceivers().contains(where: { rec -> Bool in
return rec.mailAddress.contains(searchText.lowercased())
self.searchTimer = Timer.scheduledTimer(withTimeInterval: searchDelay, repeats: false, block: { _ in
self.filterContentForSearchText(searchText, scope: scope)
})
}
default:
if let subject = mail.subject {
returnValue = subject.lowercased().contains(searchText.lowercased())
}
if !returnValue && mail.decryptedBody != nil {
returnValue = mail.decryptedBody!.lowercased().contains(searchText.lowercased())
} else if !returnValue && mail.body != nil && !mail.isEncrypted {
returnValue = mail.body!.lowercased().contains(searchText.lowercased())
}
if !returnValue && mail.cc?.count > 0 {
if let res = mail.cc?.contains(where: { cc -> Bool in
if let mail = cc as? MailAddress {
return mail.mailAddress.contains(searchText.lowercased())
/**
- parameters:
- searchText: user input string to look for
- scope : 0 = subject: 1 = body: 2 = cc + to: 3 = all
*/
private func filterContentForSearchText(_ searchText: String, scope: Int = 0) {
filteredMails = contact!.mails.filter { mail in
// a big string that we search through, contains everything from the scopes we are searching in
var str = ""
if scope == 0 || scope == 3 {
str.append(mail.subject ?? "")
}
return false
}) {
returnValue = res
if scope == 1 || scope == 3 {
if let decryptedBody = mail.decryptedBody {
str.append(decryptedBody)
} else if let body = mail.body {
str.append(body)
}
}
if !returnValue && mail.getReceivers().count > 1 {
returnValue = mail.getReceivers().contains(where: { rec -> Bool in
return rec.mailAddress.contains(searchText.lowercased())
if scope == 2 || scope == 3 {
var receivers: [MailAddress] = []
receivers.append(contentsOf: mail.getReceivers())
receivers.append(contentsOf: mail.getCCs())
// build a string of all email addresses to input in the search function
receivers.map({ addr -> String in
return addr.mailAddress
}).forEach({ addr in
str.append(addr)
})
}
}
return returnValue
return containsSearchTerms(content: str, searchText: searchText)
}
tableView.reloadData()
......@@ -259,13 +252,12 @@ class ListViewController: UITableViewController {
extension ListViewController: UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
let searchBar = searchController.searchBar
let _ = searchBar.scopeButtonTitles![searchBar.selectedScopeButtonIndex]
filterContentForSearchText(searchController.searchBar.text!, scope: searchBar.selectedScopeButtonIndex)
startSearch(searchText: searchController.searchBar.text!, scope: searchBar.selectedScopeButtonIndex)
}
}
extension ListViewController: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, selectedScopeButtonIndexDidChange selectedScope: Int) {
filterContentForSearchText(searchBar.text!, scope: selectedScope)
startSearch(searchText: searchBar.text!, scope: selectedScope)
}
}
//
// SearchHelper.swift
// enzevalos_iphone
//
// Created by lazarog98 on 26.02.20.
// Copyright © 2020 fu-berlin. All rights reserved.
//
import Foundation
/**
A collection of helper methods that are used for the different search bars
*/
/**
Function to be used to find mails that contain the search terms. All terms (separated by spaces) need to be contained in the search text.
- parameters:
- content: The String that will be searched
- searchText: Search terms (space-separated) that will be searched for
*/
func containsSearchTerms ( content : String?, searchText: String) -> Bool
{
guard searchText.count > 0 else {
///Case empty search
return true
}
guard let content = content else {
//Case Mail has no body/subject
return false
}
var longterms : [String] = []
var terms : [String] = []
//Break String into substrings separated by quoatation marks
longterms = searchText.components(separatedBy: "\"")
var i = 0
//even elements will be outside the quotation marks and need to be separated again
while (i < longterms.count)
{
if i % 2 == 0
{
terms.append(contentsOf: longterms[i].lowercased().components(separatedBy: " "))
}
else
{
terms.append(longterms[i].lowercased())
}
i+=1
}
var found = true
for t in terms
{
if !(t == "")
{
found = found && content.lowercased().contains(t)
}
}
return found
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment