Skip to content

Commit

Permalink
Added support for tagging images from web
Browse files Browse the repository at this point in the history
  • Loading branch information
Raghav Bhasin authored and Raghav Bhasin committed Aug 22, 2018
1 parent 189f543 commit 89e4911
Show file tree
Hide file tree
Showing 12 changed files with 272 additions and 8 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ fastlane/test_output
**/keys.json
**/*.pyc
**/preserve_users.txt
**/Info.plist
.DS_Store
=======
**/dracker-9443c-firebase-adminsdk-gmc2g-7d48bbd323.json
Expand Down
8 changes: 8 additions & 0 deletions ios App/Dracker.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
3C03673620FA94E900E885EB /* Friends.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C03673520FA94E900E885EB /* Friends.swift */; };
3C03673B20FAAF8B00E885EB /* FriendsDetailCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C03673A20FAAF8B00E885EB /* FriendsDetailCell.swift */; };
3C03F5C820F7EFE0002697BB /* Detail.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C03F5C720F7EFE0002697BB /* Detail.swift */; };
3C27B35D212DDA5A00093AB7 /* ImageSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C27B35C212DDA5A00093AB7 /* ImageSearch.swift */; };
3C27B361212E009E00093AB7 /* ImageLibraryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C27B360212E009E00093AB7 /* ImageLibraryCell.swift */; };
3C450B4A21054FA30083C860 /* OnboardingBankAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C450B4921054FA30083C860 /* OnboardingBankAccount.swift */; };
3C4E2B2220F7EC330053D65E /* Wallet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C4E2B2120F7EC330053D65E /* Wallet.swift */; };
3C4E2B2420F7ED160053D65E /* WalletCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3C4E2B2320F7ED160053D65E /* WalletCell.swift */; };
Expand Down Expand Up @@ -83,6 +85,8 @@
3C03673520FA94E900E885EB /* Friends.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Friends.swift; sourceTree = "<group>"; };
3C03673A20FAAF8B00E885EB /* FriendsDetailCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FriendsDetailCell.swift; sourceTree = "<group>"; };
3C03F5C720F7EFE0002697BB /* Detail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Detail.swift; sourceTree = "<group>"; };
3C27B35C212DDA5A00093AB7 /* ImageSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageSearch.swift; sourceTree = "<group>"; };
3C27B360212E009E00093AB7 /* ImageLibraryCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageLibraryCell.swift; sourceTree = "<group>"; };
3C450B4921054FA30083C860 /* OnboardingBankAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingBankAccount.swift; sourceTree = "<group>"; };
3C4E2B2120F7EC330053D65E /* Wallet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wallet.swift; sourceTree = "<group>"; };
3C4E2B2320F7ED160053D65E /* WalletCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WalletCell.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -232,6 +236,7 @@
3C81E51320F939C900693677 /* Settings.swift */,
3CF46E7620F9406B0061E15A /* Profile.swift */,
3CEAA0F120F975E1005D7D82 /* Payer.swift */,
3C27B35C212DDA5A00093AB7 /* ImageSearch.swift */,
);
path = Views;
sourceTree = "<group>";
Expand All @@ -253,6 +258,7 @@
3C96B8D520F7CB5700DDF924 /* HomeCell.swift */,
3C4E2B2320F7ED160053D65E /* WalletCell.swift */,
3C849DC0210443CA00025BC1 /* OptionsCell.swift */,
3C27B360212E009E00093AB7 /* ImageLibraryCell.swift */,
);
path = "Collection View";
sourceTree = "<group>";
Expand Down Expand Up @@ -583,6 +589,7 @@
3C03F5C820F7EFE0002697BB /* Detail.swift in Sources */,
3CEAA10520F99D73005D7D82 /* PasscodeIndicator.swift in Sources */,
3C931D3420FFBB9600C3EFEF /* Animations.swift in Sources */,
3C27B35D212DDA5A00093AB7 /* ImageSearch.swift in Sources */,
3CA9DD5F20F6EDAE000EB47F /* slide_backward.swift in Sources */,
3C03673620FA94E900E885EB /* Friends.swift in Sources */,
3C450B4A21054FA30083C860 /* OnboardingBankAccount.swift in Sources */,
Expand Down Expand Up @@ -616,6 +623,7 @@
3CCF07C32108F70900877CB2 /* Account.swift in Sources */,
3CC67E2E20F921EA0020E89A /* Note.swift in Sources */,
3CA9DD4A20F6EBFF000EB47F /* AppDelegate.swift in Sources */,
3C27B361212E009E00093AB7 /* ImageLibraryCell.swift in Sources */,
3CA9DD5D20F6ED60000EB47F /* Login.swift in Sources */,
3CF46E7720F9406B0061E15A /* Profile.swift in Sources */,
3C96B8D420F7A69E00DDF924 /* Transactions.swift in Sources */,
Expand Down
17 changes: 17 additions & 0 deletions ios App/Dracker/API/API.swift
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,22 @@ fileprivate func make_api_call(parameters: [String: String], api_endpoint: Strin
}
}


//MARK: Image Search API

func search_images_call(search_term: String, completion: ((Result<Any>) -> Void)? = nil) {
Alamofire.request(External_Endpoints.image_search, method: .get, parameters: ["q" : search_term], encoding: URLEncoding.default, headers: ["Ocp-Apim-Subscription-Key" : Search_Key]).responseJSON { response in
completion?(response.result)
}
}


func getDataFromUrl(url: URL, completion: @escaping (Data?, URLResponse?, Error?) -> ()) {
URLSession.shared.dataTask(with: url) { data, response, error in
completion(data, response, error)
}.resume()
}

//MARK: S3
func upload_to_S3(key: String, data: NSURL, bucket: AWSConstants) {
let request = AWSS3TransferManagerUploadRequest()
Expand All @@ -146,3 +162,4 @@ func upload_to_S3(key: String, data: NSURL, bucket: AWSConstants) {
let client = AWSS3TransferManager.default()
client.upload(request!)
}

27 changes: 23 additions & 4 deletions ios App/Dracker/Application Flow/Transaction/AddTransaction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class AddTransaction: UIViewController {
title.textColor = .white
title.font = UIFont.boldSystemFont(ofSize: 20)
title.text = "Add Transaction"
title.textAlignment = .center
return title
}()

Expand Down Expand Up @@ -203,8 +204,9 @@ class AddTransaction: UIViewController {
payer.frame = main_frame!
navigationController?.interactivePopGestureRecognizer?.isEnabled = false
payer.layer.transform = CATransform3DMakeTranslation(0, (main_frame?.height)!, 0)
UIView.animate(withDuration: 0.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
UIView.animate(withDuration: 0.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {[unowned self] in
payer.layer.transform = CATransform3DMakeTranslation(0, -top, 0)
self.navigation_title.text = "Select Phone"
}, completion: nil)
}

Expand Down Expand Up @@ -313,12 +315,30 @@ extension AddTransaction {
let first_responder = get_first_responder()
view.endEditing(true)
let actions = image_picker_action_sheet(controller: self, picker: picker, action1: "Tag an image from Library", action2: "Snap an image", camera: .rear, first_responder: first_responder)
actions.addAction(UIAlertAction(title: "Tag from Web", style: .default, handler: {[unowned self] (_) in
self.navigation_title.text = "Tag Image"
let top = (self.navigationController?.navigationBar.frame.height)! + UIApplication.shared.statusBarFrame.height
let main_frame = UIApplication.shared.keyWindow?.screen.bounds
let image_search = ImageSearch()
image_search.initialSearch = self.description_field.text!
image_search.parent = self
image_search.first_responder = self.get_first_responder()
image_search.render_view()
self.view.addSubview(image_search)
self.view.endEditing(true)
image_search.frame = main_frame!
self.navigationController?.interactivePopGestureRecognizer?.isEnabled = false
image_search.layer.transform = CATransform3DMakeTranslation(0, (main_frame?.height)!, 0)
UIView.animate(withDuration: 0.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
image_search.layer.transform = CATransform3DMakeTranslation(0, -top, 0)
}, completion: nil)
}))
execute_on_main { [unowned self] in
self.present(actions, animated: true, completion: nil)
}
}

fileprivate func set_options(state: state, type: action) {
func set_options(state: state, type: action) {
if state == .selected {
if type == .a_camera {
camera.setImage(#imageLiteral(resourceName: "camera_green"), for: .normal)
Expand Down Expand Up @@ -372,8 +392,7 @@ extension AddTransaction {
* This function allows to add the current item to Home View and push back to
the main controller.
*/
fileprivate func insert_and_push_back(item: Unsettled)
{
fileprivate func insert_and_push_back(item: Unsettled) {
stop_loading()
//Push back to root view controller.
navigationController?.popToRootViewController(animated: true)
Expand Down
21 changes: 21 additions & 0 deletions ios App/Dracker/Assets.xcassets/NoImage.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "NoImage.jpg",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
22 changes: 22 additions & 0 deletions ios App/Dracker/Cell Models/Collection View/ImageLibraryCell.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import UIKit

class ImageLibraryCell: BaseCollectionViewCell {

let tag_image: UIImageView = {
let image = UIImageView()
image.image = #imageLiteral(resourceName: "NoImage")
return image
}()

override func setup_cell() {
super.setup_cell()
//Add the imageView
addSubview(tag_image)
addConstraintsWithFormat(format: "H:|[v0]|", views: tag_image)
addConstraintsWithFormat(format: "V:|[v0]|", views: tag_image)
}

func load_image_from_url(url: String) {
tag_image.downloadImage(url: url)
}
}
17 changes: 17 additions & 0 deletions ios App/Dracker/Configrations/Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,23 @@ extension UIImageView {
}
}
}

func downloadImage(url: String, completion: (() -> Void)? = nil) {
if let image = cache.object(forKey: url as AnyObject) {
self.image = UIImage(data: image as! Data)
completion?()
} else {
let source = URL(string: url)
getDataFromUrl(url: source!) { data, response, error in
completion?()
guard let data = data, error == nil else { return }
cache.setObject(data as AnyObject, forKey: url as AnyObject )
DispatchQueue.main.async() {
self.image = UIImage(data: data)
}
}
}
}
}

//MARK: Currency Extension
Expand Down
3 changes: 1 addition & 2 deletions ios App/Dracker/Custom Components/ActivityImageView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ class ActivityImageView: UIImageView {
return background
}()

func start_downloading()
{
func start_downloading() {
self.addSubview(background)
let correct_frame = superview?.frame
self.activity.center = CGPoint(x: ((correct_frame?.width)! - 70.0)/2, y: frame.height/2)
Expand Down
3 changes: 1 addition & 2 deletions ios App/Dracker/Custom Components/MenuBar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ class MenuBar: UIView {

var left_anchor: NSLayoutConstraint?

func setup_slider()
{
func setup_slider() {
let slider = UIView()
slider.backgroundColor = UIColor(white: 0.95, alpha: 1)
slider.translatesAutoresizingMaskIntoConstraints = false
Expand Down
160 changes: 160 additions & 0 deletions ios App/Dracker/Views/ImageSearch.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
import UIKit

class ImageSearch: UIView {

var initialSearch: String = ""
let ID = "ImageSearchCell"
weak var parent: AddTransaction?
weak var first_responder: UITextField?
var list_of_images: [String] = []

lazy var navigation: UINavigationBar = {
let bar = UINavigationBar()
bar.isTranslucent = false
bar.tintColor = .white
let items = UINavigationItem()
bar.setItems([items], animated: true)
return bar
}()

lazy var search: UISearchController = {
let search = UISearchController(searchResultsController: nil)
search.hidesNavigationBarDuringPresentation = false
search.definesPresentationContext = false
search.searchBar.isTranslucent = true
search.searchResultsUpdater = self
search.searchBar.placeholder = "Tag Image..."
search.delegate = self
search.obscuresBackgroundDuringPresentation = false
search.searchBar.keyboardType = .phonePad
return search
}()

let status_bar: UIView = {
let view = UIView()
view.backgroundColor = .theme
return view
}()

let search_view: UIView = {
let view = UIView()
return view
}()

lazy var imageLibrary: UICollectionView = {
let library = UICollectionView(frame: frame, collectionViewLayout: UICollectionViewFlowLayout())
library.dataSource = self
library.delegate = self
library.backgroundColor = .white
library.register(ImageLibraryCell.self, forCellWithReuseIdentifier: ID)
library.contentInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
library.showsHorizontalScrollIndicator = false
library.showsVerticalScrollIndicator = false
return library
}()

override init(frame: CGRect) {
super.init(frame: frame)
setup()
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

fileprivate func setup() {
backgroundColor = .white
addSubview(navigation)
addSubview(status_bar)
addSubview(search_view)
addSubview(imageLibrary)
let height = UIApplication.shared.statusBarFrame.height
addConstraintsWithFormat(format: "H:|[v0]|", views: navigation)
addConstraintsWithFormat(format: "H:|[v0]|", views: search_view)
addConstraintsWithFormat(format: "H:|[v0]|", views: imageLibrary)
addConstraintsWithFormat(format: "H:|[v0]|", views: status_bar)
addConstraintsWithFormat(format: "V:|-\(height)-[v0][v1(50)]-5-[v2]|", views: navigation, search_view ,imageLibrary)
addConstraintsWithFormat(format: "V:|[v0(\(height))]", views: status_bar)
search_view.addSubview(search.searchBar)
search.searchBar.sizeToFit()
}

func render_view() {
search.searchBar.text = initialSearch
}
}

//MARK: Searching Delegates

extension ImageSearch: UISearchResultsUpdating, UISearchControllerDelegate {
func updateSearchResults(for searchController: UISearchController) {
let term = searchController.searchBar.text!
if term == "" { return }
search_images_call(search_term: term) {[unowned self] (data) in
if data.isFailure {
return
}
let result = data.value as! [String: Any]
if result["mesage"] != nil {
return
}
let items = result["value"] as! [[String: Any]]
for item in items {
let url = item["contentUrl"] as! String
self.list_of_images.append(url)
}
execute_on_main {
self.imageLibrary.reloadData()
}
}
}

fileprivate func send_back() {
search.dismiss(animated: true, completion: nil)
UIView.animate(withDuration: 0.8, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseOut, animations: {
self.layer.transform = CATransform3DMakeTranslation(0, self.frame.height, 0)
}){[unowned self] (_) in
self.first_responder?.becomeFirstResponder()
self.parent?.navigationController?.interactivePopGestureRecognizer?.isEnabled = true
self.removeFromSuperview()
}
}

}

//MARK: Image Library Delegates
extension ImageSearch: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = imageLibrary.dequeueReusableCell(withReuseIdentifier: ID, for: indexPath) as! ImageLibraryCell
cell.load_image_from_url(url: list_of_images[indexPath.row])
return cell
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return list_of_images.count
}

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let item = imageLibrary.cellForItem(at: indexPath) as! ImageLibraryCell
let image = item.tag_image.image!
parent?.image_url = image.get_temporary_path(quality: 0.50)
parent?.navigation_title.text = "Add Transaction"
parent?.set_options(state: .selected, type: .a_camera)
send_back()
}
}


//MARK: Collection View Flow Layout
extension ImageSearch: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 112, height: 112)
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 8
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 8
}
}
Loading

0 comments on commit 89e4911

Please sign in to comment.