Commit b39593cc authored by Andreas Traczyk's avatar Andreas Traczyk Committed by Kateryna Kostiuk

connectivity: add network connection monitoring

- Adds Reachability via Carthage

Change-Id: Id4043c33afd4b62a5b69e285126eb301d924047f
Reviewed-by: Kateryna Kostiuk's avatarKateryna Kostiuk <kateryna.kostiuk@savoirfairelinux.com>
parent 153b2b5d
......@@ -5,3 +5,4 @@ github "AliSoftware/Reusable" ~> 4.0
github "SwiftyBeaver/SwiftyBeaver"
github "ViccAlexander/Chameleon"
github "andreamazz/AMPopTip"
github "ashleymills/Reachability.swift"
......@@ -5,5 +5,6 @@ github "RxSwiftCommunity/RxRealm" "0.6.0"
github "SwiftyBeaver/SwiftyBeaver" "1.4.2"
github "ViccAlexander/Chameleon" "2.2.0"
github "andreamazz/AMPopTip" "3.0.2"
github "ashleymills/Reachability.swift" "v4.1.0"
github "pkluz/PKHUD" "4.2.3"
github "realm/realm-cocoa" "v2.8.3"
......@@ -201,6 +201,8 @@
62A88D371F6C2ED400F8AB18 /* PresenceAdapterDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A88D361F6C2ED400F8AB18 /* PresenceAdapterDelegate.swift */; };
62A88D391F6C323500F8AB18 /* PresenceAdapter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 62A88D381F6C323500F8AB18 /* PresenceAdapter.mm */; };
62A88D3B1F6C3ACC00F8AB18 /* PresenceService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62A88D3A1F6C3ACC00F8AB18 /* PresenceService.swift */; };
62DFAB2C1F9FF030002D6F9C /* Reachability.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62DFAB2B1F9FF030002D6F9C /* Reachability.framework */; };
62DFAB2E1F9FF0D0002D6F9C /* NetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62DFAB2D1F9FF0D0002D6F9C /* NetworkService.swift */; };
62E55B6D1F758E6F00D3FEF4 /* String+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E55B6C1F758E6F00D3FEF4 /* String+Helpers.swift */; };
62E55B6F1F793ADE00D3FEF4 /* AvatarsColors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62E55B6E1F793ADE00D3FEF4 /* AvatarsColors.swift */; };
/* End PBXBuildFile section */
......@@ -445,6 +447,8 @@
62A88D361F6C2ED400F8AB18 /* PresenceAdapterDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresenceAdapterDelegate.swift; sourceTree = "<group>"; };
62A88D381F6C323500F8AB18 /* PresenceAdapter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PresenceAdapter.mm; sourceTree = "<group>"; };
62A88D3A1F6C3ACC00F8AB18 /* PresenceService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PresenceService.swift; sourceTree = "<group>"; };
62DFAB2B1F9FF030002D6F9C /* Reachability.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Reachability.framework; path = Carthage/Build/iOS/Reachability.framework; sourceTree = "<group>"; };
62DFAB2D1F9FF0D0002D6F9C /* NetworkService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkService.swift; sourceTree = "<group>"; };
62E55B6C1F758E6F00D3FEF4 /* String+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+Helpers.swift"; sourceTree = "<group>"; };
62E55B6E1F793ADE00D3FEF4 /* AvatarsColors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarsColors.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
......@@ -492,6 +496,7 @@
04399AFB1D1C341A00E99CD9 /* libpjmedia-codec.a in Frameworks */,
04399AFC1D1C341A00E99CD9 /* libpjmedia-videodev.a in Frameworks */,
04399AFD1D1C341A00E99CD9 /* libpjmedia.a in Frameworks */,
62DFAB2C1F9FF030002D6F9C /* Reachability.framework in Frameworks */,
04399AFE1D1C341A00E99CD9 /* libpjnath.a in Frameworks */,
04399AFF1D1C341A00E99CD9 /* libpjsip-simple.a in Frameworks */,
04399B001D1C341A00E99CD9 /* libpjsip-ua.a in Frameworks */,
......@@ -563,6 +568,7 @@
isa = PBXGroup;
children = (
0ED6660F1F9FED1C00743D42 /* AMPopTip.framework */,
62DFAB2B1F9FF030002D6F9C /* Reachability.framework */,
0EEFBA3B1F83DA21000EDBAD /* libsecp256k1.a */,
1A3CA32A1F102BB700283748 /* Chameleon.framework */,
1A1E476E1F0E894600EA9A36 /* SwiftyBeaver.framework */,
......@@ -597,6 +603,7 @@
1A5DC01F1F355DCF0075E8EF /* ContactsService.swift */,
62A88D361F6C2ED400F8AB18 /* PresenceAdapterDelegate.swift */,
62A88D3A1F6C3ACC00F8AB18 /* PresenceService.swift */,
62DFAB2D1F9FF0D0002D6F9C /* NetworkService.swift */,
);
path = Services;
sourceTree = "<group>";
......@@ -1285,6 +1292,7 @@
"$(SRCROOT)/Carthage/Build/iOS/SwiftyBeaver.framework",
"$(SRCROOT)/Carthage/Build/iOS/Chameleon.framework",
"$(SRCROOT)/Carthage/build/iOS/AMPopTip.framework",
"$(SRCROOT)/Carthage/Build/iOS/Reachability.framework",
);
name = "⚙️ Copy Frameworks";
outputPaths = (
......@@ -1423,6 +1431,7 @@
564C44621E943DE6000F92B1 /* NameService.swift in Sources */,
1A5DC02C1F3565250075E8EF /* MeViewController.swift in Sources */,
1A2041801F1E903B00C08435 /* CreateProfileViewController.swift in Sources */,
62DFAB2E1F9FF0D0002D6F9C /* NetworkService.swift in Sources */,
0EDE34C91F8691BB00FFA15C /* EditProfileViewModel.swift in Sources */,
04399AAD1D1C304300E99CD9 /* DRingAdapter.mm in Sources */,
1A2D18D11F29182500B2C785 /* ConversationViewController.swift in Sources */,
......
......@@ -37,6 +37,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
private let conversationsService = ConversationsService(withMessageAdapter: MessagesAdapter())
private let contactsService = ContactsService(withContactsAdapter: ContactsAdapter())
private let presenceService = PresenceService(withPresenceAdapter: PresenceAdapter())
private let networkService = NetworkService()
public lazy var injectionBag: InjectionBag = {
return InjectionBag(withDaemonService: self.daemonService,
......@@ -44,7 +45,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
withNameService: self.nameService,
withConversationService: self.conversationsService,
withContactsService: self.contactsService,
withPresenceService: self.presenceService)
withPresenceService: self.presenceService,
withNetworkService: self.networkService
)
}()
private lazy var appCoordinator: AppCoordinator = {
return AppCoordinator(with: self.injectionBag)
......@@ -69,6 +72,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
SystemAdapter().registerConfigurationHandler()
self.startDaemon()
self.networkService.monitorNetworkType()
// themetize the app
Chameleon.setGlobalThemeUsingPrimaryColor(UIColor.ringMain, withSecondaryColor: UIColor.ringSecondary, andContentStyle: .light)
Chameleon.setRingThemeUsingPrimaryColor(UIColor.ringMain, withSecondaryColor: UIColor.ringSecondary, andContentStyle: .light)
......
......@@ -51,6 +51,7 @@ enum Asset {
static let device = ImageAsset(name: "device")
static let icContactPicture = ImageAsset(name: "ic_contact_picture")
static let logoRingBeta2Blanc = ImageAsset(name: "logo-ring-beta2-blanc")
static let settingsIcon = ImageAsset(name: "settings_icon")
// swiftlint:disable trailing_comma
static let allColors: [ColorAsset] = [
......@@ -61,6 +62,7 @@ enum Asset {
device,
icContactPicture,
logoRingBeta2Blanc,
settingsIcon,
]
// swiftlint:enable trailing_comma
@available(*, deprecated, renamed: "allImages")
......
......@@ -118,8 +118,12 @@ enum L10n {
}
enum Smartlist {
/// Be sure cellular access is granted in your settings
static let cellularAccess = L10n.tr("Localizable", "smartlist.cellularAccess")
/// Conversations
static let conversations = L10n.tr("Localizable", "smartlist.conversations")
/// No network connectivity
static let noNetworkConnectivity = L10n.tr("Localizable", "smartlist.noNetworkConnectivity")
/// No results
static let noResults = L10n.tr("Localizable", "smartlist.noResults")
/// Searching...
......
......@@ -29,19 +29,22 @@ class InjectionBag {
let conversationsService: ConversationsService
let contactsService: ContactsService
let presenceService: PresenceService
let networkService: NetworkService
init (withDaemonService daemonService: DaemonService,
withAccountService accountService: AccountsService,
withNameService nameService: NameService,
withConversationService conversationService: ConversationsService,
withContactsService contactsService: ContactsService,
withPresenceService presenceService: PresenceService) {
withPresenceService presenceService: PresenceService,
withNetworkService networkService: NetworkService) {
self.daemonService = daemonService
self.accountService = accountService
self.nameService = nameService
self.conversationsService = conversationService
self.contactsService = contactsService
self.presenceService = presenceService
self.networkService = networkService
}
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="12121" systemVersion="16F73" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Raw-Ee-7sK">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13196" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="Raw-Ee-7sK">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="12089"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13174"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
......@@ -21,8 +21,59 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="e5o-cY-djH" userLabel="Network Alert View">
<rect key="frame" x="0.0" y="76" width="375" height="56"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="HKv-H1-GYI" userLabel="Alert Labels View">
<rect key="frame" x="171" y="0.0" width="33" height="56"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Fu7-Dr-XvA" userLabel="Network Alert Label">
<rect key="frame" x="-2.5" y="10" width="37.5" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" misplaced="YES" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dHy-gp-i6K" userLabel="Cellular Alert Label">
<rect key="frame" x="101" y="55" width="37.5" height="18"/>
<fontDescription key="fontDescription" type="system" pointSize="13"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<constraints>
<constraint firstItem="Fu7-Dr-XvA" firstAttribute="top" secondItem="HKv-H1-GYI" secondAttribute="top" constant="10" id="SAj-hd-YiO"/>
<constraint firstItem="Fu7-Dr-XvA" firstAttribute="centerX" secondItem="HKv-H1-GYI" secondAttribute="centerX" id="apx-hI-eg9"/>
<constraint firstAttribute="height" constant="56" id="j6O-zU-YVL"/>
<constraint firstAttribute="width" secondItem="dHy-gp-i6K" secondAttribute="width" id="mfY-pK-Ush"/>
<constraint firstItem="dHy-gp-i6K" firstAttribute="centerX" secondItem="HKv-H1-GYI" secondAttribute="centerX" id="orq-Lq-Fmo"/>
<constraint firstItem="dHy-gp-i6K" firstAttribute="top" secondItem="Fu7-Dr-XvA" secondAttribute="bottom" id="pOy-bX-Jpj"/>
</constraints>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="iaz-fd-fEz" userLabel="Settings Button">
<rect key="frame" x="220" y="16" width="24" height="24"/>
<accessibility key="accessibilityConfiguration">
<accessibilityTraits key="traits" button="YES" image="YES"/>
</accessibility>
<constraints>
<constraint firstAttribute="height" constant="24" id="d6g-Zu-vR7"/>
<constraint firstAttribute="width" constant="24" id="nbF-R8-5kY"/>
</constraints>
<state key="normal" image="settings_icon"/>
</button>
</subviews>
<color key="backgroundColor" red="0.94117647058823528" green="0.4392156862745098" blue="0.4392156862745098" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstItem="iaz-fd-fEz" firstAttribute="leading" secondItem="HKv-H1-GYI" secondAttribute="trailing" constant="16" id="AFY-4C-aBu"/>
<constraint firstItem="HKv-H1-GYI" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="e5o-cY-djH" secondAttribute="leading" constant="10" id="QoG-HF-kux"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="iaz-fd-fEz" secondAttribute="trailing" constant="10" id="VGV-dn-yaS"/>
<constraint firstItem="HKv-H1-GYI" firstAttribute="centerY" secondItem="e5o-cY-djH" secondAttribute="centerY" id="jtZ-C0-Lms"/>
<constraint firstAttribute="height" constant="56" id="qrO-B9-Qmw"/>
<constraint firstItem="iaz-fd-fEz" firstAttribute="centerY" secondItem="e5o-cY-djH" secondAttribute="centerY" id="xx8-oG-TVU"/>
<constraint firstItem="HKv-H1-GYI" firstAttribute="centerX" secondItem="e5o-cY-djH" secondAttribute="centerX" priority="750" id="yI5-9z-dUv"/>
</constraints>
</view>
<searchBar contentMode="redraw" placeholder="Enter name..." translatesAutoresizingMaskIntoConstraints="NO" id="xPr-nI-I35">
<rect key="frame" x="0.0" y="20" width="375" height="44"/>
<rect key="frame" x="0.0" y="20" width="375" height="56"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<color key="tintColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
<offsetWrapper key="searchFieldBackgroundPositionAdjustment" horizontal="0.0" vertical="0.0"/>
......@@ -32,14 +83,14 @@
</connections>
</searchBar>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="HFM-G6-hMN">
<rect key="frame" x="0.0" y="64" width="375" height="603"/>
<rect key="frame" x="0.0" y="132" width="375" height="535"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</tableView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="EvL-Bu-O1T">
<rect key="frame" x="0.0" y="64" width="375" height="603"/>
<rect key="frame" x="0.0" y="132" width="375" height="535"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="No conversations" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="8bB-XU-6gh">
<rect key="frame" x="121.5" y="291" width="133" height="21"/>
<rect key="frame" x="121.5" y="257" width="133" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
<nil key="highlightedColor"/>
......@@ -47,12 +98,12 @@
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="8bB-XU-6gh" firstAttribute="centerY" secondItem="EvL-Bu-O1T" secondAttribute="centerY" id="PQg-Np-JN3"/>
<constraint firstItem="8bB-XU-6gh" firstAttribute="centerX" secondItem="EvL-Bu-O1T" secondAttribute="centerX" id="gY7-3l-mS7"/>
<constraint firstItem="8bB-XU-6gh" firstAttribute="centerY" secondItem="EvL-Bu-O1T" secondAttribute="centerY" id="1R2-tE-dtX"/>
<constraint firstItem="8bB-XU-6gh" firstAttribute="centerX" secondItem="EvL-Bu-O1T" secondAttribute="centerX" id="PCa-ph-Sbp"/>
</constraints>
</view>
<tableView hidden="YES" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="1" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="opE-y7-3Rm">
<rect key="frame" x="0.0" y="64" width="375" height="603"/>
<rect key="frame" x="0.0" y="132" width="375" height="535"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<label key="tableHeaderView" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="4Yu-Fe-ixq">
<rect key="frame" x="0.0" y="0.0" width="375" height="24"/>
......@@ -71,15 +122,18 @@
<constraint firstItem="xPr-nI-I35" firstAttribute="leading" secondItem="2dZ-8A-4nq" secondAttribute="leading" id="4NO-53-KBh"/>
<constraint firstAttribute="trailing" secondItem="HFM-G6-hMN" secondAttribute="trailing" id="7H1-ka-2Ti"/>
<constraint firstItem="HFM-G6-hMN" firstAttribute="leading" secondItem="2dZ-8A-4nq" secondAttribute="leading" id="8tr-Rd-1kr"/>
<constraint firstItem="HFM-G6-hMN" firstAttribute="top" secondItem="xPr-nI-I35" secondAttribute="bottom" id="9lS-x7-SaG"/>
<constraint firstItem="e5o-cY-djH" firstAttribute="top" secondItem="xPr-nI-I35" secondAttribute="bottom" id="CLm-6J-lYv"/>
<constraint firstAttribute="trailing" secondItem="opE-y7-3Rm" secondAttribute="trailing" id="D0f-nM-KEs"/>
<constraint firstItem="HFM-G6-hMN" firstAttribute="top" secondItem="e5o-cY-djH" secondAttribute="bottom" id="KK7-rp-AZz"/>
<constraint firstItem="opE-y7-3Rm" firstAttribute="top" secondItem="e5o-cY-djH" secondAttribute="bottom" id="NKz-A0-hLf"/>
<constraint firstItem="xPr-nI-I35" firstAttribute="top" secondItem="sbJ-yn-t3e" secondAttribute="bottom" id="OX7-et-d3F"/>
<constraint firstItem="cfq-zl-uux" firstAttribute="top" secondItem="EvL-Bu-O1T" secondAttribute="bottom" id="TsM-9H-eI1"/>
<constraint firstItem="cfq-zl-uux" firstAttribute="top" secondItem="HFM-G6-hMN" secondAttribute="bottom" id="VfB-5H-uHq"/>
<constraint firstItem="opE-y7-3Rm" firstAttribute="top" secondItem="xPr-nI-I35" secondAttribute="bottom" id="aeg-VV-nOD"/>
<constraint firstItem="EvL-Bu-O1T" firstAttribute="top" secondItem="e5o-cY-djH" secondAttribute="bottom" id="aH0-7e-i4a"/>
<constraint firstAttribute="trailing" secondItem="xPr-nI-I35" secondAttribute="trailing" id="dtX-d4-r9P"/>
<constraint firstItem="EvL-Bu-O1T" firstAttribute="top" secondItem="xPr-nI-I35" secondAttribute="bottom" id="izx-u2-l6g"/>
<constraint firstAttribute="trailing" secondItem="e5o-cY-djH" secondAttribute="trailing" id="k9v-18-oxL"/>
<constraint firstAttribute="trailing" secondItem="EvL-Bu-O1T" secondAttribute="trailing" id="nSK-QH-snj"/>
<constraint firstItem="e5o-cY-djH" firstAttribute="leading" secondItem="2dZ-8A-4nq" secondAttribute="leading" id="rXu-fF-ESz"/>
<constraint firstItem="cfq-zl-uux" firstAttribute="top" secondItem="opE-y7-3Rm" secondAttribute="bottom" id="wun-hC-1JP"/>
</constraints>
</view>
......@@ -87,11 +141,15 @@
<tabBarItem key="tabBarItem" title="Home" id="o5c-No-Dpq"/>
<navigationItem key="navigationItem" id="zLl-0A-Dht"/>
<connections>
<outlet property="cellularAlertLabel" destination="dHy-gp-i6K" id="W9w-Mi-GTY"/>
<outlet property="conversationsTableView" destination="HFM-G6-hMN" id="M97-IB-NUZ"/>
<outlet property="networkAlertLabel" destination="Fu7-Dr-XvA" id="0qV-lk-9mE"/>
<outlet property="networkAlertViewTopConstraint" destination="CLm-6J-lYv" id="LEO-Ep-Gpx"/>
<outlet property="noConversationsView" destination="EvL-Bu-O1T" id="tVV-6a-4Xg"/>
<outlet property="searchBar" destination="xPr-nI-I35" id="Y3U-rV-yfc"/>
<outlet property="searchResultsTableView" destination="opE-y7-3Rm" id="F3g-9d-IQt"/>
<outlet property="searchTableViewLabel" destination="4Yu-Fe-ixq" id="dq3-QM-bfA"/>
<outlet property="settingsButton" destination="iaz-fd-fEz" id="R2O-R8-BDk"/>
<outlet property="tableView" destination="HFM-G6-hMN" id="Gci-vk-ijr"/>
</connections>
</viewController>
......@@ -99,5 +157,25 @@
</objects>
<point key="canvasLocation" x="-97.5" y="-1177.8169014084508"/>
</scene>
<!--View Controller-->
<scene sceneID="YBM-c2-EWl">
<objects>
<viewController id="9uj-4q-nGi" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="EEa-ZN-DDP"/>
<viewControllerLayoutGuide type="bottom" id="VVG-rs-LcN"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="zCu-ae-k0m">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="bOs-td-edL" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
<resources>
<image name="settings_icon" width="24" height="24"/>
</resources>
</document>
......@@ -44,6 +44,10 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
@IBOutlet weak var searchBar: UISearchBar!
@IBOutlet weak var noConversationsView: UIView!
@IBOutlet weak var searchTableViewLabel: UILabel!
@IBOutlet weak var networkAlertLabel: UILabel!
@IBOutlet weak var cellularAlertLabel: UILabel!
@IBOutlet weak var networkAlertViewTopConstraint: NSLayoutConstraint!
@IBOutlet weak var settingsButton: UIButton!
// MARK: members
var viewModel: SmartlistViewModel!
......@@ -77,6 +81,31 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
.bind(to: self.noConversationsView.rx.isHidden)
.disposed(by: disposeBag)
self.networkAlertViewTopConstraint.constant = self.viewModel.networkConnectionState() == .none ? 0.0 : -56.0
self.networkAlertLabel.text = L10n.Smartlist.noNetworkConnectivity
self.cellularAlertLabel.text = L10n.Smartlist.cellularAccess
self.viewModel.connectionState
.subscribe(onNext: { connectionState in
let newAlertHeight = connectionState == .none ? 0.0 : -56.0
UIView.animate(withDuration: 0.25) {
self.networkAlertViewTopConstraint.constant = CGFloat(newAlertHeight)
self.view.layoutIfNeeded()
}
})
.disposed(by: self.disposeBag)
self.settingsButton.backgroundColor = nil
self.settingsButton.rx.tap.subscribe(onNext: { _ in
if let url = URL(string: UIApplicationOpenSettingsURLString) {
if #available(iOS 10.0, *) {
UIApplication.shared.open(url, completionHandler: nil)
} else {
UIApplication.shared.openURL(url)
}
}
}).disposed(by: self.disposeBag)
self.navigationItem.rightBarButtonItem = self.editButtonItem
}
......@@ -256,6 +285,11 @@ class SmartlistViewController: UIViewController, StoryboardBased, ViewModelBased
self.searchBar.returnKeyType = .done
self.searchBar.layer.shadowColor = UIColor.black.cgColor
self.searchBar.layer.shadowOpacity = 0.5
self.searchBar.layer.shadowOffset = CGSize.zero
self.searchBar.layer.shadowRadius = 2
//Bind the SearchBar to the ViewModel
self.searchBar.rx.text.orEmpty
.debounce(Durations.textFieldThrottlingDuration.value, scheduler: MainScheduler.instance)
......
......@@ -19,9 +19,12 @@
*/
import RxSwift
import SwiftyBeaver
class SmartlistViewModel: Stateable, ViewModel {
private let log = SwiftyBeaver.self
// MARK: - Rx Stateable
private let stateSubject = PublishSubject<State>()
lazy var state: Observable<State> = {
......@@ -35,6 +38,7 @@ class SmartlistViewModel: Stateable, ViewModel {
fileprivate let nameService: NameService
fileprivate let accountsService: AccountsService
fileprivate let contactsService: ContactsService
fileprivate let networkService: NetworkService
let searchBarText = Variable<String>("")
var isSearching: Observable<Bool>!
......@@ -42,17 +46,30 @@ class SmartlistViewModel: Stateable, ViewModel {
var searchResults: Observable<[ConversationSection]>!
var hideNoConversationsMessage: Observable<Bool>!
var searchStatus = PublishSubject<String>()
var connectionState = PublishSubject<ConnectionType>()
fileprivate var filteredResults = Variable([ConversationViewModel]())
fileprivate var contactFoundConversation = Variable<ConversationViewModel?>(nil)
fileprivate var conversationViewModels = [ConversationViewModel]()
func networkConnectionState() -> ConnectionType {
return self.networkService.connectionState.value
}
required init(with injectionBag: InjectionBag) {
self.conversationsService = injectionBag.conversationsService
self.nameService = injectionBag.nameService
self.accountsService = injectionBag.accountService
self.contactsService = injectionBag.contactsService
self.networkService = injectionBag.networkService
// Observe connectivity changes
self.networkService.connectionStateObservable
.subscribe(onNext: { value in
self.connectionState.onNext(value)
})
.disposed(by: self.disposeBag)
//Create observable from sorted conversations and flatMap them to view models
let conversationsObservable: Observable<[ConversationViewModel]> = self.conversationsService.conversations.asObservable().map({ conversations in
......
......@@ -84,6 +84,11 @@
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
......
{
"images" : [
{
"idiom" : "universal",
"filename" : "ic_settings.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "ic_settings_2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "ic_settings_3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
......@@ -30,6 +30,8 @@
"smartlist.conversations" = "Conversations";
"smartlist.searching" = "Searching...";
"smartlist.noResults" = "No results";
"smartlist.noNetworkConnectivity" = "No network connectivity";
"smartlist.cellularAccess" = "Be sure cellular access is granted in your settings";
// Walkthrough
......
/*
* Copyright (C) 2017 Savoir-faire Linux Inc.
*
* Author: Andreas Traczyk <andreas.traczyk@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 Reachability
import SwiftyBeaver
import RxSwift
enum ConnectionType {
case none
case wifi
case cellular
}
class NetworkService {
private let log = SwiftyBeaver.self
let reachability: Reachability!
var connectionState = Variable<ConnectionType>(.none)
lazy var connectionStateObservable: Observable<ConnectionType> = {
return self.connectionState.asObservable()
}()
init() {
reachability = Reachability()!
}
func monitorNetworkType() {
reachability.whenReachable = { reachability in
if reachability.connection == .wifi {
self.connectionState.value = .wifi
} else {
self.connectionState.value = .cellular
}
}
reachability.whenUnreachable = { _ in
self.connectionState.value = .none
}
do {
try reachability.startNotifier()
self.log.debug("network notifier started")
} catch {
self.log.debug("unable to start network notifier")
}
}
}
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