This repository has been archived by the owner on Jun 7, 2020. It is now read-only.
[NEW] In-app notifications #1504
Merged
rafaelks
merged 51 commits into
RocketChat:develop
from
Sameesunkaria:local-notifications
Apr 13, 2018
Merged
Changes from 25 commits
Commits
Show all changes
51 commits
Select commit
Hold shift + click to select a range
f7c4901
minor refactoring
Sameesunkaria 6085621
added subscription for notifications
Sameesunkaria fc24d67
Merged with upstream
Sameesunkaria e27f01e
Merge branch 'local-notifications' into develop
Sameesunkaria 24d043f
Merge develop into local-notifications
Sameesunkaria b66f2df
Added Animation
Sameesunkaria e52f14d
Merge branch 'develop' into pr/12
Sameesunkaria 2bf9dad
Notification view constraints changed
Sameesunkaria 0af288b
Merge branch 'develop' into local-notifications
Sameesunkaria ecc11fe
Notification view controller moved to nib.
Sameesunkaria 7a66afd
Notification view positioned correctly
Sameesunkaria e14c9a4
Merged with upstream
Sameesunkaria 4cd3e16
Notification view now responds to touches
Sameesunkaria 3ac8f90
Merge remote-tracking branch 'origin/local-notifications' into local-…
Sameesunkaria 9010632
Added notification manager
Sameesunkaria 01a5539
Removed notification view nib
Sameesunkaria 5b02f35
Removed Animation
Sameesunkaria 869a982
Resolved conflict
Sameesunkaria 2c75db7
Merge branch 'develop' into local-notifications
rafaelks 0f13d34
Added notification sound.
Sameesunkaria 344c6ff
App name corrected
Sameesunkaria 785dd8d
Added slide out
Sameesunkaria 0628365
Merged with upstream
Sameesunkaria 90ddc4a
Tests added
Sameesunkaria 6e0950c
Added test cases
Sameesunkaria 52e9960
Refactoring tests
Sameesunkaria 668342b
Added post notification test
Sameesunkaria b9fa5f8
Added test cases
Sameesunkaria 29c6010
Added descriptions
Sameesunkaria 510d455
Added support for opening private rooms
Sameesunkaria 3ea4b4d
Added test cases for open rooms
Sameesunkaria 36a42cc
Added tests for notification view constraints
Sameesunkaria 0f2a2bd
Fixed sizing issues.
Sameesunkaria 895603f
Minor refactoring
Sameesunkaria a85c471
ChatNotification structure updated
Sameesunkaria 66f4d44
Indented correctly
Sameesunkaria d7c6f7c
Indentation fixed
Sameesunkaria f7e16f1
Restructured ChatNotification
Sameesunkaria 1508813
Changed access control identifier on internalType
Sameesunkaria 153845e
Merge branch 'develop' of https://github.com/RocketChat/Rocket.Chat.i…
cardoso 45c32eb
Merge branch 'local-notifications' of https://github.com/Sameesunkari…
cardoso 8470abf
Merge branch 'develop' of https://github.com/RocketChat/Rocket.Chat.i…
cardoso 222dd1c
Merge branch 'develop' of https://github.com/RocketChat/Rocket.Chat.i…
cardoso 7031ab0
Fix some code style issues
cardoso e230919
Merge branch 'local-notifications' of github.com:Sameesunkaria/Rocket…
rafaelks 8fc5e75
Disabled in-app notification sound and push notifications when the so…
Sameesunkaria cc142d3
Merge with upstream
Sameesunkaria e69c2e3
Notification window test added
Sameesunkaria 3b960d7
Merge remote-tracking branch 'origin/local-notifications' into local-…
Sameesunkaria 82ef06a
Merge branch 'local-notifications' of github.com:Sameesunkaria/Rocket…
rafaelks 0d7e844
Merge branch 'develop' of github.com:RocketChat/Rocket.Chat.iOS into …
rafaelks File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
142 changes: 142 additions & 0 deletions
142
Rocket.Chat/Controllers/Notification/NotificationViewController.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
// | ||
// NotificationViewController.swift | ||
// Rocket.Chat | ||
// | ||
// Created by Samar Sunkaria on 4/3/18. | ||
// Copyright © 2018 Rocket.Chat. All rights reserved. | ||
// | ||
|
||
import UIKit | ||
import AudioToolbox | ||
|
||
class NotificationViewController: UIViewController { | ||
|
||
static let shared = NotificationViewController(nibName: "NotificationViewController", bundle: nil) | ||
|
||
@IBOutlet weak var notificationView: NotificationView! | ||
@IBOutlet private weak var hiddenConstraint: NSLayoutConstraint! | ||
@IBOutlet private weak var visibleConstraint: NSLayoutConstraint! | ||
|
||
var lastTouchLocation: CGPoint? | ||
let animationDuration = 0.3 | ||
|
||
var notificationViewIsHidden: Bool { | ||
get { | ||
if let visibleConstraint = visibleConstraint, visibleConstraint.isActive { | ||
return false | ||
} | ||
return true | ||
} | ||
|
||
set { | ||
visibleConstraint?.isActive = !newValue | ||
hiddenConstraint?.isActive = newValue | ||
(UIApplication.shared.value(forKey: "statusBarWindow") as? UIWindow)?.alpha = newValue ? 1 : 0 | ||
} | ||
} | ||
|
||
override func viewDidLoad() { | ||
super.viewDidLoad() | ||
view.layer.shadowColor = UIColor.black.cgColor | ||
view.layer.shadowOpacity = 0.3 | ||
view.layer.shadowRadius = 8.0 | ||
view.layer.shadowOffset = CGSize(width: 0, height: 0) | ||
view.clipsToBounds = true | ||
} | ||
|
||
override func viewWillLayoutSubviews() { | ||
super.viewWillLayoutSubviews() | ||
|
||
visibleConstraint.constant = 8 | ||
if #available(iOS 11.0, *) { | ||
if view.safeAreaInsets.top > 20 { | ||
visibleConstraint.constant = 38 | ||
} | ||
} | ||
} | ||
|
||
weak var timer: Timer? { | ||
willSet { | ||
timer?.invalidate() | ||
} | ||
} | ||
|
||
func displayNotification(title: String, body: String, username: String) { | ||
guard let notificationView = notificationView else { return } | ||
|
||
notificationView.displayNotification(title: title, body: body, username: username) | ||
playSound() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think about not playing any sound for now? Until we have a setting for that, I would with no sound. Let's just comment the code maybe :-) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure. I was kinda on the fence about it anyway. |
||
|
||
UIView.animate(withDuration: animationDuration) { | ||
self.notificationViewIsHidden = false | ||
self.view.layoutIfNeeded() | ||
} | ||
|
||
timer = Timer.scheduledTimer(withTimeInterval: 6.0, repeats: false) { _ in | ||
UIView.animate(withDuration: self.animationDuration) { | ||
self.notificationViewIsHidden = true | ||
self.view.layoutIfNeeded() | ||
} | ||
} | ||
} | ||
|
||
private func playSound() { | ||
guard let soundUrl = Bundle.main.url(forResource: "chime", withExtension: "mp3") else { return } | ||
var soundId: SystemSoundID = 0 | ||
AudioServicesCreateSystemSoundID(soundUrl as CFURL, &soundId) | ||
AudioServicesPlayAlertSound(soundId) | ||
} | ||
|
||
} | ||
|
||
extension NotificationViewController { | ||
@IBAction func handleTap(_ sender: UITapGestureRecognizer) { | ||
if sender.state == .ended { | ||
NotificationManager.shared.didRespondToNotification() | ||
timer?.fire() | ||
} | ||
} | ||
|
||
@IBAction func handlePan(_ sender: UIPanGestureRecognizer) { | ||
guard let notificationView = notificationView, !notificationViewIsHidden else { return } | ||
switch sender.state { | ||
case .began: | ||
lastTouchLocation = sender.location(in: view) | ||
|
||
case .changed: | ||
guard let lastTouchLocation = lastTouchLocation else { return } | ||
let displacement = sender.location(in: view).y - lastTouchLocation.y | ||
let newYOffset = notificationView.frame.origin.y + displacement | ||
|
||
if newYOffset <= visibleConstraint.constant { | ||
notificationView.frame.origin.y += displacement | ||
self.lastTouchLocation = sender.location(in: view) | ||
|
||
} else if notificationView.bounds.contains(sender.location(in: notificationView)), | ||
newYOffset <= visibleConstraint.constant + 16 { | ||
notificationView.frame.origin.y += displacement / 10 | ||
self.lastTouchLocation = sender.location(in: view) | ||
} | ||
|
||
case .ended: | ||
lastTouchLocation = nil | ||
if sender.velocity(in: view).y < -25 { | ||
timer?.fire() | ||
} else { | ||
view.setNeedsLayout() | ||
UIView.animate(withDuration: animationDuration) { | ||
self.view.layoutIfNeeded() | ||
} | ||
} | ||
|
||
case .cancelled: | ||
lastTouchLocation = nil | ||
view.setNeedsLayout() | ||
UIView.animate(withDuration: animationDuration) { | ||
self.view.layoutIfNeeded() | ||
} | ||
|
||
default: break | ||
} | ||
} | ||
} |
114 changes: 114 additions & 0 deletions
114
Rocket.Chat/Controllers/Notification/NotificationViewController.xib
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14109" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> | ||
<device id="retina4_7" orientation="portrait"> | ||
<adaptation id="fullscreen"/> | ||
</device> | ||
<dependencies> | ||
<deployment identifier="iOS"/> | ||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/> | ||
<capability name="Alignment constraints to the first baseline" minToolsVersion="6.0"/> | ||
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/> | ||
<capability name="Baseline standard spacing" minToolsVersion="9.0"/> | ||
<capability name="Safe area layout guides" minToolsVersion="9.0"/> | ||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> | ||
</dependencies> | ||
<objects> | ||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="NotificationViewController" customModule="Rocket_Chat" customModuleProvider="target"> | ||
<connections> | ||
<outlet property="hiddenConstraint" destination="iSN-ku-uLM" id="kxi-dT-Kgj"/> | ||
<outlet property="notificationView" destination="PHK-lk-IxG" id="0pR-AZ-ZxP"/> | ||
<outlet property="view" destination="iN0-l3-epB" id="0Rj-yq-cb5"/> | ||
<outlet property="visibleConstraint" destination="1Q8-oE-2ed" id="ucf-ab-b77"/> | ||
</connections> | ||
</placeholder> | ||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> | ||
<view contentMode="scaleToFill" id="iN0-l3-epB"> | ||
<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="PHK-lk-IxG" customClass="NotificationView" customModule="Rocket_Chat" customModuleProvider="target"> | ||
<rect key="frame" x="8" y="-85.5" width="359" height="69.5"/> | ||
<subviews> | ||
<visualEffectView opaque="NO" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2Sn-Lw-2jc"> | ||
<rect key="frame" x="0.0" y="0.0" width="359" height="70"/> | ||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | ||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" ambiguous="YES" insetsLayoutMarginsFromSafeArea="NO" id="4JV-l7-f9r"> | ||
<rect key="frame" x="0.0" y="0.0" width="359" height="70"/> | ||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | ||
<gestureRecognizers/> | ||
</view> | ||
<blurEffect style="extraLight"/> | ||
</visualEffectView> | ||
<label opaque="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="252" text="Title" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pSR-mg-fTE"> | ||
<rect key="frame" x="69" y="12.5" width="282" height="20.5"/> | ||
<fontDescription key="fontDescription" type="boldSystem" pointSize="17"/> | ||
<nil key="textColor"/> | ||
<nil key="highlightedColor"/> | ||
</label> | ||
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="KOK-7t-SFa"> | ||
<rect key="frame" x="12" y="12.5" width="45" height="45"/> | ||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> | ||
<constraints> | ||
<constraint firstAttribute="height" constant="45" id="AsH-aH-Iwh"/> | ||
<constraint firstAttribute="width" secondItem="KOK-7t-SFa" secondAttribute="height" multiplier="1:1" id="dcq-yW-PH5"/> | ||
</constraints> | ||
</view> | ||
<label opaque="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Body" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Khg-Fj-whL"> | ||
<rect key="frame" x="69" y="36.5" width="282" height="20.5"/> | ||
<fontDescription key="fontDescription" type="system" pointSize="17"/> | ||
<color key="textColor" red="0.26051741839999998" green="0.2605243921" blue="0.260520637" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> | ||
<nil key="highlightedColor"/> | ||
</label> | ||
</subviews> | ||
<color key="backgroundColor" white="0.99409537845187712" alpha="0.0" colorSpace="calibratedWhite"/> | ||
<gestureRecognizers/> | ||
<constraints> | ||
<constraint firstItem="Khg-Fj-whL" firstAttribute="firstBaseline" secondItem="pSR-mg-fTE" secondAttribute="baseline" constant="24" symbolType="layoutAnchor" id="48X-KW-GjT"/> | ||
<constraint firstAttribute="trailing" secondItem="pSR-mg-fTE" secondAttribute="trailing" constant="8" id="4QG-mg-IcO"/> | ||
<constraint firstAttribute="trailing" secondItem="Khg-Fj-whL" secondAttribute="trailing" constant="8" id="4jL-fR-L6n"/> | ||
<constraint firstItem="KOK-7t-SFa" firstAttribute="top" secondItem="PHK-lk-IxG" secondAttribute="top" constant="12" id="7ly-Q4-bZu"/> | ||
<constraint firstAttribute="width" relation="lessThanOrEqual" constant="550" id="G6K-9l-94u"/> | ||
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="Khg-Fj-whL" secondAttribute="bottom" constant="8" id="eon-ja-4kU"/> | ||
<constraint firstAttribute="height" relation="lessThanOrEqual" constant="150" id="g82-JC-2h2"/> | ||
<constraint firstAttribute="bottom" secondItem="KOK-7t-SFa" secondAttribute="bottom" priority="250" constant="12" id="glb-6O-WiY"/> | ||
<constraint firstItem="KOK-7t-SFa" firstAttribute="leading" secondItem="PHK-lk-IxG" secondAttribute="leading" constant="12" id="kXI-LJ-aGu"/> | ||
<constraint firstItem="pSR-mg-fTE" firstAttribute="top" secondItem="KOK-7t-SFa" secondAttribute="top" id="oFE-M9-Shc"/> | ||
<constraint firstItem="Khg-Fj-whL" firstAttribute="leading" secondItem="KOK-7t-SFa" secondAttribute="trailing" constant="12" id="rl6-k2-chZ"/> | ||
<constraint firstItem="pSR-mg-fTE" firstAttribute="leading" secondItem="KOK-7t-SFa" secondAttribute="trailing" constant="12" id="y9T-ub-deS"/> | ||
</constraints> | ||
<connections> | ||
<outlet property="avatarViewContainer" destination="KOK-7t-SFa" id="pg6-OP-A6F"/> | ||
<outlet property="bodyLabel" destination="Khg-Fj-whL" id="GaY-eI-DdQ"/> | ||
<outlet property="titleLabel" destination="pSR-mg-fTE" id="f4g-xL-MX6"/> | ||
<outletCollection property="gestureRecognizers" destination="0eg-LY-yJc" appends="YES" id="6lE-PV-105"/> | ||
<outletCollection property="gestureRecognizers" destination="MDE-Cs-C7p" appends="YES" id="68S-Ej-0vb"/> | ||
</connections> | ||
</view> | ||
</subviews> | ||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/> | ||
<constraints> | ||
<constraint firstItem="PHK-lk-IxG" firstAttribute="width" secondItem="iN0-l3-epB" secondAttribute="width" priority="750" constant="-16" id="0jV-re-AIy"/> | ||
<constraint firstItem="PHK-lk-IxG" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="8" id="1Q8-oE-2ed"/> | ||
<constraint firstItem="PHK-lk-IxG" firstAttribute="centerX" secondItem="vUN-kp-3ea" secondAttribute="centerX" id="GSl-WQ-03d"/> | ||
<constraint firstAttribute="top" secondItem="PHK-lk-IxG" secondAttribute="bottom" constant="16" id="iSN-ku-uLM"/> | ||
</constraints> | ||
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/> | ||
<variation key="default"> | ||
<mask key="constraints"> | ||
<exclude reference="1Q8-oE-2ed"/> | ||
</mask> | ||
</variation> | ||
<point key="canvasLocation" x="34.5" y="69.5"/> | ||
</view> | ||
<tapGestureRecognizer id="0eg-LY-yJc"> | ||
<connections> | ||
<action selector="handleTap:" destination="-1" id="ci7-Qi-5JF"/> | ||
</connections> | ||
</tapGestureRecognizer> | ||
<panGestureRecognizer minimumNumberOfTouches="1" id="MDE-Cs-C7p"> | ||
<connections> | ||
<action selector="handlePan:" destination="-1" id="SLu-y0-hoL"/> | ||
</connections> | ||
</panGestureRecognizer> | ||
</objects> | ||
</document> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 52 additions & 0 deletions
52
Rocket.Chat/Managers/Model/SubscriptionManager/SubscriptionManager+Messages.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
// | ||
// SubscriptionManager+Messages.swift | ||
// Rocket.Chat | ||
// | ||
// Created by Samar Sunkaria on 4/3/18. | ||
// Copyright © 2018 Rocket.Chat. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
|
||
extension SubscriptionManager { | ||
static func markAsRead(_ subscription: Subscription, completion: @escaping MessageCompletion) { | ||
let request = [ | ||
"msg": "method", | ||
"method": "readMessages", | ||
"params": [subscription.rid] | ||
] as [String: Any] | ||
|
||
SocketManager.send(request) { response in | ||
guard !response.isError() else { return Log.debug(response.result.string) } | ||
completion(response) | ||
} | ||
} | ||
|
||
static func sendTextMessage(_ message: Message, completion: @escaping MessageCompletion) { | ||
|
||
let request = [ | ||
"msg": "method", | ||
"method": "sendMessage", | ||
"params": [[ | ||
"_id": message.identifier ?? "", | ||
"rid": message.subscription.rid, | ||
"msg": message.text | ||
]] | ||
] as [String: Any] | ||
|
||
SocketManager.send(request) { (response) in | ||
guard !response.isError() else { return Log.debug(response.result.string) } | ||
completion(response) | ||
} | ||
} | ||
|
||
static func toggleFavorite(_ subscription: Subscription, completion: @escaping MessageCompletion) { | ||
let request = [ | ||
"msg": "method", | ||
"method": "toggleFavorite", | ||
"params": [subscription.rid, !subscription.favorite] | ||
] as [String: Any] | ||
|
||
SocketManager.send(request, completion: completion) | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain the changes in this file?
"Rocket.Chat.ShareExtension/Info.plist"
If they are accidental changes, you can revert them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe Xcode has a habit of reordering them. I’ll revert the changes.