Commit d8b60072 authored by Kateryna Kostiuk's avatar Kateryna Kostiuk

Profile: create during initial walkthrough

Create profile when app is launched for first time

Change-Id: Ia81fec3ca9ad79c7e55548b9cdd3ad0f1223ff73
Reviewed-by: Andreas Traczyk's avatarAndreas Traczyk <andreas.traczyk@savoirfairelinux.com>
parent 00695c69
......@@ -82,6 +82,8 @@
0586C94B1F684DF600613517 /* UIImage+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0586C94A1F684DF600613517 /* UIImage+Helpers.swift */; };
0E403F811F7D797300C80BC2 /* MessageCellGenerated.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E403F801F7D797300C80BC2 /* MessageCellGenerated.swift */; };
0E403F831F7D79B000C80BC2 /* MessageCellGenerated.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0E403F821F7D79B000C80BC2 /* MessageCellGenerated.xib */; };
0EDE34C71F868E1200FFA15C /* EditProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE34C61F868E1200FFA15C /* EditProfileViewController.swift */; };
0EDE34C91F8691BB00FFA15C /* EditProfileViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EDE34C81F8691BB00FFA15C /* EditProfileViewModel.swift */; };
0EE1B54E1F75ACDE00BA98EE /* CNContactVCardSerialization+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE1B54D1F75ACDE00BA98EE /* CNContactVCardSerialization+Helpers.swift */; };
0EE1B5501F75AD4700BA98EE /* VCardUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0EE1B54F1F75AD4700BA98EE /* VCardUtils.swift */; };
0EEFBA3C1F83DA21000EDBAD /* libsecp256k1.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0EEFBA3B1F83DA21000EDBAD /* libsecp256k1.a */; };
......@@ -300,6 +302,8 @@
0586C94A1F684DF600613517 /* UIImage+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIImage+Helpers.swift"; sourceTree = "<group>"; };
0E403F801F7D797300C80BC2 /* MessageCellGenerated.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageCellGenerated.swift; sourceTree = "<group>"; };
0E403F821F7D79B000C80BC2 /* MessageCellGenerated.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MessageCellGenerated.xib; sourceTree = "<group>"; };
0EDE34C61F868E1200FFA15C /* EditProfileViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditProfileViewController.swift; sourceTree = "<group>"; };
0EDE34C81F8691BB00FFA15C /* EditProfileViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditProfileViewModel.swift; sourceTree = "<group>"; };
0EE1B54D1F75ACDE00BA98EE /* CNContactVCardSerialization+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CNContactVCardSerialization+Helpers.swift"; sourceTree = "<group>"; };
0EE1B54F1F75AD4700BA98EE /* VCardUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VCardUtils.swift; sourceTree = "<group>"; };
0EEFBA3B1F83DA21000EDBAD /* libsecp256k1.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libsecp256k1.a; path = ../DEPS/arm64/lib/libsecp256k1.a; sourceTree = "<group>"; };
......@@ -769,9 +773,19 @@
name = SYS_DEPS;
sourceTree = "<group>";
};
0EDE34C51F868D2D00FFA15C /* Shared */ = {
isa = PBXGroup;
children = (
0EDE34C61F868E1200FFA15C /* EditProfileViewController.swift */,
0EDE34C81F8691BB00FFA15C /* EditProfileViewModel.swift */,
);
name = Shared;
sourceTree = "<group>";
};
1A0C4EBC1F1D48AA00550433 /* Features */ = {
isa = PBXGroup;
children = (
0EDE34C51F868D2D00FFA15C /* Shared */,
1A0C4EBD1F1D48DD00550433 /* Walkthrough */,
1A2D18A71F290FAA00B2C785 /* Conversations */,
1A5DC0331F3567080075E8EF /* ContactRequests */,
......@@ -1288,6 +1302,7 @@
1A3D28A71F0EB9DB00B524EE /* Bool+String.swift in Sources */,
5516C29F1E71CEFF009D3D2D /* AccountModelHelper.swift in Sources */,
1ABE07D31F0D8FE800D36361 /* Storyboards.swift in Sources */,
0EDE34C71F868E1200FFA15C /* EditProfileViewController.swift in Sources */,
62A88D3B1F6C3ACC00F8AB18 /* PresenceService.swift in Sources */,
1A2D18E51F29197100B2C785 /* MessageAccessoryView.swift in Sources */,
1A2D18C61F29180700B2C785 /* ConversationModel.swift in Sources */,
......@@ -1333,6 +1348,7 @@
564C44621E943DE6000F92B1 /* NameService.swift in Sources */,
1A5DC02C1F3565250075E8EF /* MeViewController.swift in Sources */,
1A2041801F1E903B00C08435 /* CreateProfileViewController.swift in Sources */,
0EDE34C91F8691BB00FFA15C /* EditProfileViewModel.swift in Sources */,
04399AAD1D1C304300E99CD9 /* DRingAdapter.mm in Sources */,
1A2D18D11F29182500B2C785 /* ConversationViewController.swift in Sources */,
0EE1B5501F75AD4700BA98EE /* VCardUtils.swift in Sources */,
......
......@@ -26,6 +26,10 @@ enum VCardFolders: String {
case contacts
case profile
}
enum VCardFiles: String {
case myProfile
}
class VCardUtils {
class func saveVCard(vCard: CNContact, withName name: String, inFolder folder: String) -> Observable<Void> {
......
......@@ -85,10 +85,10 @@ class AppCoordinator: Coordinator, StateableResponsive {
let walkthroughCoordinator = WalkthroughCoordinator(with: self.injectionBag)
self.addChildCoordinator(childCoordinator: walkthroughCoordinator)
let walkthroughViewController = walkthroughCoordinator.rootViewController
self.present(viewController: walkthroughViewController, withStyle: .popup, withAnimation: true)
self.present(viewController: walkthroughViewController, withStyle: .popup, withAnimation: false)
walkthroughCoordinator.start()
walkthroughViewController.rx.viewDidDisappear.subscribe(onNext: { [weak self, weak walkthroughCoordinator] (_) in
walkthroughViewController.rx.controllerWasDismissed.subscribe(onNext: { [weak self, weak walkthroughCoordinator] (_) in
walkthroughCoordinator?.stateSubject.dispose()
self?.removeChildCoordinator(childCoordinator: walkthroughCoordinator)
}).disposed(by: self.disposeBag)
......
/*
* Copyright (C) 2017 Savoir-faire Linux Inc.
*
* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
import UIKit
import Reusable
import RxSwift
class EditProfileViewController: UIViewController, UITextFieldDelegate, UIImagePickerControllerDelegate, UINavigationControllerDelegate {
// MARK: - outlets
@IBOutlet weak var profileImageView: UIImageView!
@IBOutlet weak var profileName: UITextField!
// MARK: - members
var model: EditProfileViewModel!
fileprivate let disposeBag = DisposeBag()
// MARK: - functions
override func viewDidLoad() {
super.viewDidLoad()
self.model = EditProfileViewModel()
self.setupUI()
}
func setupUI() {
self.model.image.asObservable()
.bind(to: self.profileImageView.rx.image)
.disposed(by: disposeBag)
self.model.profileName.asObservable()
.bind(to: self.profileName.rx.text)
.disposed(by: disposeBag)
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
profileImageView.isUserInteractionEnabled = true
profileImageView.addGestureRecognizer(tapGestureRecognizer)
//Binds the keyboard Send button action to the ViewModel
self.profileName.rx.controlEvent(.editingDidEndOnExit).subscribe(onNext: { [unowned self] _ in
self.model.updateName(self.profileName.text!)
}).disposed(by: disposeBag)
}
func imageTapped(tapGestureRecognizer: UITapGestureRecognizer) {
let alert = UIAlertController.init(title: nil,
message: nil,
preferredStyle: .actionSheet)
let cameraAction = UIAlertAction(title: L10n.Alerts.profileTakePhoto, style: UIAlertActionStyle.default) { _ in
self.takePicture()
}
let pictureAction = UIAlertAction(title: L10n.Alerts.profileUploadPhoto, style: UIAlertActionStyle.default) { _ in
self.importPicture()
}
let cancelAction = UIAlertAction(title: L10n.Alerts.profileCancelPhoto, style: UIAlertActionStyle.cancel)
alert.addAction(cameraAction)
alert.addAction(pictureAction)
alert.addAction(cancelAction)
alert.popoverPresentationController?.sourceView = self.view
alert.popoverPresentationController?.permittedArrowDirections = UIPopoverArrowDirection()
alert.popoverPresentationController?.sourceRect = CGRect(x: self.view.bounds.midX, y: self.view.bounds.maxX, width: 0, height: 0)
self.present(alert, animated: true, completion: nil)
}
func takePicture() {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
imagePicker.cameraDevice = UIImagePickerControllerCameraDevice.front
imagePicker.allowsEditing = true
imagePicker.modalPresentationStyle = .overFullScreen
self.present(imagePicker, animated: true, completion: nil)
}
}
func importPicture() {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.allowsEditing = true
imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
imagePicker.modalPresentationStyle = .overFullScreen
self.present(imagePicker, animated: true, completion: nil)
}
// MARK: - Delegates
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any]) {
var image: UIImage!
if let img = info[UIImagePickerControllerEditedImage] as? UIImage {
image = img
} else if let img = info[UIImagePickerControllerOriginalImage] as? UIImage {
image = img
}
image = image.convert(toSize: CGSize(width: 100.0, height: 100.0), scale: UIScreen.main.scale)
self.model.updateImage(image)
profileImageView.contentMode = .scaleAspectFit
profileImageView.image = image.circleMasked
dismiss(animated: true, completion: nil)
}
//hide keyboard when touch outside of text field
// override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// self.profileName.resignFirstResponder()
// self.profileName.text = self.model.profileName.value
// }
}
/*
* Copyright (C) 2017 Savoir-faire Linux Inc.
*
* Author: Kateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
import Foundation
import RxSwift
import Contacts
class EditProfileViewModel {
let disposeBag = DisposeBag()
let defaultImage = Image(named: "ic_contact_picture")
var image = Variable<Image?>(nil)
var profileName = Variable<String>("")
init() {
self.image.value = defaultImage
VCardUtils.loadVCard(named: VCardFiles.myProfile.rawValue, inFolder: VCardFolders.profile.rawValue) .subscribe(onSuccess: { [unowned self]card in
self.profileName.value = card.familyName
if let data = card.imageData {
self.image.value = UIImage(data: data)?.convert(toSize: CGSize(width: 100.0, height: 100.0), scale: UIScreen.main.scale).circleMasked
}
}).disposed(by: disposeBag)
}
func saveProfile() {
let vcard = CNMutableContact()
if let image = self.image.value, !image.isEqual(defaultImage) {
vcard.imageData = UIImagePNGRepresentation(image)
}
vcard.familyName = self.profileName.value
_ = VCardUtils.saveVCard(vCard: vcard, withName: VCardFiles.myProfile.rawValue, inFolder: VCardFolders.profile.rawValue).subscribe()
}
func updateImage(_ image: Image) {
self.image.value = image
self.saveProfile()
}
func updateName(_ name: String) {
self.profileName.value = name
self.saveProfile()
}
}
......@@ -72,4 +72,13 @@ extension Reactive where Base : UIViewController {
let source = self.sentMessage(#selector(Base.didReceiveMemoryWarning)).map { _ in }
return ControlEvent(events: source)
}
public var controllerWasDismissed: ControlEvent<Bool> {
let source = self.sentMessage(#selector(Base.viewWillDisappear)).filter { _ in
return self.base.isBeingDismissed
}.map { $0.first as? Bool ?? false }
return ControlEvent(events: source)
}
}
......@@ -253,9 +253,8 @@ class ConversationViewModel: ViewModel {
}
func sendContactRequest() {
let contactExists = self.contactsService.contact(withRingId: self.conversation.recipientRingId) != nil ? true : false
self.accountService.loadVCard(forAccounr: self.accountService.currentAccount!)
VCardUtils.loadVCard(named: VCardFiles.myProfile.rawValue, inFolder: VCardFolders.profile.rawValue)
.subscribe(onSuccess: { [unowned self] (card) in
self.contactsService.sendContactRequest(toContactRingId: self.conversation.recipientRingId, vCard: card, withAccount: self.accountService.currentAccount!)
.subscribe(onCompleted: {
......
......@@ -22,79 +22,99 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="PERSON PLACEHOLDER" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="w8x-Sv-T50">
<rect key="frame" x="16" y="30" width="343" height="26.5"/>
<fontDescription key="fontDescription" type="system" pointSize="22"/>
<color key="textColor" red="0.20000000300000001" green="0.20000000300000001" blue="0.20000000300000001" alpha="1" colorSpace="calibratedRGB"/>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Ring id" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="11" translatesAutoresizingMaskIntoConstraints="NO" id="rC6-Ga-QjY" userLabel="RingId Label">
<rect key="frame" x="21" y="189" width="333" height="18"/>
<constraints>
<constraint firstAttribute="height" constant="18" id="UsR-G7-bkE"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" red="0.29803922770000002" green="0.29803922770000002" blue="0.29803922770000002" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Ring id" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="11" translatesAutoresizingMaskIntoConstraints="NO" id="rC6-Ga-QjY" userLabel="RingId Label">
<rect key="frame" x="16" y="66.5" width="343" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" red="0.29803922770000002" green="0.29803922770000002" blue="0.29803922770000002" alpha="1" colorSpace="calibratedRGB"/>
<textField opaque="NO" clipsSubviews="YES" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" placeholder="Enter name" textAlignment="center" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GCe-jT-OCG">
<rect key="frame" x="36" y="140" width="303" height="26"/>
<nil key="textColor"/>
<fontDescription key="fontDescription" name="HelveticaNeue-Bold" family="Helvetica Neue" pointSize="21"/>
<textInputTraits key="textInputTraits" autocorrectionType="no" returnKeyType="done"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="color" keyPath="borderColor">
<color key="value" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
<real key="value" value="0.0"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</textField>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="tS0-P7-fYT">
<rect key="frame" x="20" y="167" width="335" height="1"/>
<constraints>
<constraint firstAttribute="height" constant="1" id="f7M-6A-gFC"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="number" keyPath="borderWidth">
<real key="value" value="2"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="borderColor">
<color key="value" name="gridColor" catalog="System" colorSpace="catalog"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="gradientStartColor">
<color key="value" name="gridColor" catalog="System" colorSpace="catalog"/>
</userDefinedRuntimeAttribute>
<userDefinedRuntimeAttribute type="color" keyPath="gradientEndColor">
<color key="value" name="gridColor" catalog="System" colorSpace="catalog"/>
</userDefinedRuntimeAttribute>
</userDefinedRuntimeAttributes>
</label>
<stackView opaque="NO" contentMode="center" distribution="fillEqually" alignment="center" translatesAutoresizingMaskIntoConstraints="NO" id="reK-Om-ReA">
<rect key="frame" x="16" y="232.5" width="343" height="30"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Rfv-Ak-7NM">
<rect key="frame" x="0.0" y="0.0" width="171.5" height="30"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<color key="tintColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<state key="normal" title="Take a picture">
<color key="titleColor" red="0.40000000600000002" green="0.40000000600000002" blue="0.40000000600000002" alpha="1" colorSpace="calibratedRGB"/>
</state>
<connections>
<action selector="takePicture:" destination="MXJ-Bb-hGu" eventType="touchDown" id="M3f-W6-cfc"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="hq2-0j-DsW">
<rect key="frame" x="171.5" y="0.0" width="171.5" height="30"/>
<state key="normal" title="Import a picture">
<color key="titleColor" red="0.40000000600000002" green="0.40000000600000002" blue="0.40000000600000002" alpha="1" colorSpace="calibratedRGB"/>
</state>
<connections>
<action selector="importPicture:" destination="MXJ-Bb-hGu" eventType="touchDown" id="Cgc-Uj-vJE"/>
</connections>
</button>
</subviews>
</stackView>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="ic_contact_picture" translatesAutoresizingMaskIntoConstraints="NO" id="8HY-Zl-94u">
<rect key="frame" x="16" y="104.5" width="343" height="128"/>
<rect key="frame" x="137" y="10" width="100" height="100"/>
<constraints>
<constraint firstAttribute="height" constant="100" id="3Ik-A7-Cyx"/>
<constraint firstAttribute="width" constant="100" id="xE6-h0-miE"/>
</constraints>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="PERSON PLACEHOLDER" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="w8x-Sv-T50">
<rect key="frame" x="21" y="212" width="333" height="23"/>
<fontDescription key="fontDescription" type="system" pointSize="19"/>
<color key="textColor" red="0.20000000300000001" green="0.20000000300000001" blue="0.20000000300000001" alpha="1" colorSpace="calibratedRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="trailingMargin" secondItem="8HY-Zl-94u" secondAttribute="trailing" id="8Uy-Pp-lgo"/>
<constraint firstItem="rC6-Ga-QjY" firstAttribute="leading" secondItem="nkh-py-Uar" secondAttribute="leadingMargin" id="IQi-1b-isC"/>
<constraint firstItem="rC6-Ga-QjY" firstAttribute="trailing" secondItem="nkh-py-Uar" secondAttribute="trailingMargin" id="Rkf-1X-wgP"/>
<constraint firstItem="8HY-Zl-94u" firstAttribute="top" secondItem="rC6-Ga-QjY" secondAttribute="bottom" constant="20" id="ZZS-Wh-23Z"/>
<constraint firstItem="8HY-Zl-94u" firstAttribute="leading" secondItem="nkh-py-Uar" secondAttribute="leadingMargin" id="ceB-3O-BOQ"/>
<constraint firstItem="rC6-Ga-QjY" firstAttribute="top" secondItem="w8x-Sv-T50" secondAttribute="bottom" constant="10" id="lnm-Mq-ocY"/>
<constraint firstItem="w8x-Sv-T50" firstAttribute="leading" secondItem="nkh-py-Uar" secondAttribute="leadingMargin" id="nMK-tO-WU0"/>
<constraint firstItem="w8x-Sv-T50" firstAttribute="top" secondItem="SYf-gf-IKh" secondAttribute="bottom" constant="10" id="rUH-Jk-nMV"/>
<constraint firstAttribute="trailingMargin" secondItem="reK-Om-ReA" secondAttribute="trailing" id="tUZ-Io-Jbc"/>
<constraint firstItem="w8x-Sv-T50" firstAttribute="trailing" secondItem="nkh-py-Uar" secondAttribute="trailingMargin" id="uYH-if-S88"/>
<constraint firstItem="reK-Om-ReA" firstAttribute="leading" secondItem="nkh-py-Uar" secondAttribute="leadingMargin" id="w47-Gi-x8l"/>
<constraint firstItem="reK-Om-ReA" firstAttribute="top" secondItem="8HY-Zl-94u" secondAttribute="bottom" id="zEx-uZ-4SL"/>
<constraint firstAttribute="trailingMargin" secondItem="rC6-Ga-QjY" secondAttribute="trailing" constant="5" id="4mU-no-jxy"/>
<constraint firstItem="tS0-P7-fYT" firstAttribute="leading" secondItem="nkh-py-Uar" secondAttribute="leading" constant="20" id="6OH-dg-fT7"/>
<constraint firstAttribute="trailingMargin" secondItem="w8x-Sv-T50" secondAttribute="trailing" constant="5" id="Bm3-S8-KXr"/>
<constraint firstItem="GCe-jT-OCG" firstAttribute="top" secondItem="8HY-Zl-94u" secondAttribute="bottom" constant="30" id="E9u-9R-kVg"/>
<constraint firstItem="8HY-Zl-94u" firstAttribute="top" secondItem="nkh-py-Uar" secondAttribute="topMargin" constant="10" id="FBb-kO-4nV"/>
<constraint firstItem="tS0-P7-fYT" firstAttribute="top" secondItem="GCe-jT-OCG" secondAttribute="bottom" constant="1" id="FGU-ae-3wK"/>
<constraint firstItem="8HY-Zl-94u" firstAttribute="centerX" secondItem="nkh-py-Uar" secondAttribute="centerX" id="H4W-Vc-cHV"/>
<constraint firstAttribute="trailingMargin" secondItem="GCe-jT-OCG" secondAttribute="trailing" constant="20" id="I2l-64-P0x"/>
<constraint firstItem="tS0-P7-fYT" firstAttribute="centerX" secondItem="nkh-py-Uar" secondAttribute="centerX" id="JBF-Pu-rcp"/>
<constraint firstItem="GCe-jT-OCG" firstAttribute="leading" secondItem="nkh-py-Uar" secondAttribute="leadingMargin" constant="20" id="Sp4-fa-qoR"/>
<constraint firstAttribute="trailing" secondItem="tS0-P7-fYT" secondAttribute="trailing" constant="20" id="Uvb-ZR-7rf"/>
<constraint firstItem="GCe-jT-OCG" firstAttribute="centerX" secondItem="nkh-py-Uar" secondAttribute="centerX" id="WO3-X1-ObR"/>
<constraint firstItem="rC6-Ga-QjY" firstAttribute="leading" secondItem="nkh-py-Uar" secondAttribute="leadingMargin" constant="5" id="g4K-vz-fbY"/>
<constraint firstItem="w8x-Sv-T50" firstAttribute="top" secondItem="rC6-Ga-QjY" secondAttribute="bottom" constant="5" id="kSt-bN-hIG"/>
<constraint firstItem="w8x-Sv-T50" firstAttribute="leading" secondItem="rC6-Ga-QjY" secondAttribute="leading" id="t75-yu-OEC"/>
<constraint firstItem="rC6-Ga-QjY" firstAttribute="top" secondItem="tS0-P7-fYT" secondAttribute="bottom" constant="21" id="yve-5B-6tl"/>
</constraints>
</view>
<extendedEdge key="edgesForExtendedLayout" bottom="YES"/>
<tabBarItem key="tabBarItem" title="Me" id="AKc-Hb-EHr"/>
<navigationItem key="navigationItem" id="vC8-Ti-TTd">
<barButtonItem key="rightBarButtonItem" systemItem="edit" id="NqP-iv-qav"/>
</navigationItem>
<navigationItem key="navigationItem" id="vC8-Ti-TTd"/>
<connections>
<outlet property="importButton" destination="hq2-0j-DsW" id="TJA-fa-k8g"/>
<outlet property="nameLabel" destination="w8x-Sv-T50" id="OAT-b7-q3U"/>
<outlet property="photoButton" destination="Rfv-Ak-7NM" id="Hl5-bN-0CV"/>
<outlet property="profileImageView" destination="8HY-Zl-94u" id="RQx-NQ-Ezs"/>
<outlet property="ringIdLabel" destination="rC6-Ga-QjY" id="McC-Ah-cfF"/>
<outlet property="nameLabel" destination="w8x-Sv-T50" id="IgU-9F-Fkh"/>
<outlet property="profileImageView" destination="8HY-Zl-94u" id="cY6-cO-WEq"/>
<outlet property="profileName" destination="GCe-jT-OCG" id="FDX-fX-Fye"/>
<outlet property="ringIdLabel" destination="rC6-Ga-QjY" id="nsg-Jw-OTS"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="MXJ-Bb-hGu" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-94" y="-438"/>
<point key="canvasLocation" x="-186.40000000000001" y="-483.50824587706148"/>
</scene>
</scenes>
<resources>
......
......@@ -22,14 +22,11 @@ import UIKit
import Reusable
import RxSwift
class MeViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate, StoryboardBased, ViewModelBased {
class MeViewController: EditProfileViewController, StoryboardBased, ViewModelBased {
// MARK: - outlets
@IBOutlet weak var nameLabel: UILabel!
@IBOutlet weak var ringIdLabel: UILabel!
@IBOutlet weak var profileImageView: UIImageView!
@IBOutlet weak var importButton: UIButton!
@IBOutlet weak var photoButton: UIButton!
// MARK: - members
var viewModel: MeViewModel!
......@@ -38,14 +35,12 @@ class MeViewController: UIViewController, UIImagePickerControllerDelegate, UINav
// MARK: - functions
override func viewDidLoad() {
super.viewDidLoad()
self.title = L10n.Global.meTabBarTitle
self.navigationItem.title = L10n.Global.meTabBarTitle
self.setupUI()
}
func setupUI() {
override func setupUI() {
self.viewModel.userName.asObservable()
.bind(to: self.nameLabel.rx.text)
.disposed(by: disposeBag)
......@@ -54,81 +49,6 @@ class MeViewController: UIViewController, UIImagePickerControllerDelegate, UINav
.bind(to: self.ringIdLabel.rx.text)
.disposed(by: disposeBag)
self.viewModel.image?.asObservable()
.bind(to: self.profileImageView.rx.image)
.disposed(by: disposeBag)
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped(tapGestureRecognizer:)))
profileImageView.isUserInteractionEnabled = true
profileImageView.addGestureRecognizer(tapGestureRecognizer)
photoButton.rx.tap.subscribe(onNext: {
self.takePicture()
}).disposed(by: self.disposeBag)
photoButton.backgroundColor = UIColor(white: 1, alpha: 0)
importButton.rx.tap.subscribe(onNext: {
self.importPicture()
}).disposed(by: self.disposeBag)
importButton.backgroundColor = UIColor(white: 1, alpha: 0)
}
func imageTapped(tapGestureRecognizer: UITapGestureRecognizer) {
}
func takePicture() {
if UIImagePickerController.isSourceTypeAvailable(UIImagePickerControllerSourceType.camera) {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.sourceType = UIImagePickerControllerSourceType.camera
imagePicker.cameraDevice = UIImagePickerControllerCameraDevice.front
imagePicker.allowsEditing = true
self.present(imagePicker, animated: true, completion: nil)
}
}
func importPicture() {
let imagePicker = UIImagePickerController()
imagePicker.delegate = self
imagePicker.allowsEditing = true
imagePicker.sourceType = UIImagePickerControllerSourceType.photoLibrary
self.present(imagePicker, animated: true, completion: nil)
}
// MARK: - Delegates
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
var image: UIImage!
if let img = info[UIImagePickerControllerEditedImage] as? UIImage {
image = img
} else if let img = info[UIImagePickerControllerOriginalImage] as? UIImage {
image = img
}
image = image.convert(toSize:CGSize(width:100.0, height:100.0), scale: UIScreen.main.scale)
self.viewModel.saveProfile(withImage: image)
profileImageView.contentMode = .scaleAspectFit
profileImageView.image = image.circleMasked
dismiss(animated:true, completion: nil)
super.setupUI()
}
// MARK: - QRCode
// func createQRFromString(_ str: String) {
//
// let data = str.data(using: String.Encoding.isoLatin1, allowLossyConversion: false)
//
// let filter = CIFilter(name: "CIQRCodeGenerator")
// filter!.setValue(data, forKey: "inputMessage")
//
// let qrImage: CIImage = filter!.outputImage!