Skip to content

Commit

Permalink
Merge pull request #39 from ibm-bluemix-mobile-services/development
Browse files Browse the repository at this point in the history
In app feedback implementation for ios
  • Loading branch information
mohlogan authored Apr 25, 2018
2 parents 7ed3a73 + 68f6a24 commit 370475c
Show file tree
Hide file tree
Showing 71 changed files with 14,572 additions and 33 deletions.
4 changes: 4 additions & 0 deletions .slather.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
coverage_service: coveralls
xcodeproj: BMSAnalytics.xcodeproj
scheme: BMSAnalytics iOS
ignore:
- Source/SSZipArchive/*
- Source/Feedback/ComposeEditorViewController.swift
- Source/Feedback/UIImageControllerViewController.swift
18 changes: 12 additions & 6 deletions BMSAnalytics.podspec
Original file line number Diff line number Diff line change
@@ -1,23 +1,29 @@
Pod::Spec.new do |s|

s.name = 'BMSAnalytics'
s.version = '2.2.4'
s.version = '2.2.5'
s.summary = 'The analytics component of the Swift client SDK for IBM Bluemix Mobile Services'
s.homepage = 'https://github.com/ibm-bluemix-mobile-services/bms-clientsdk-swift-analytics'
s.documentation_url = 'https://ibm-bluemix-mobile-services.github.io/API-docs/client-SDK/BMSAnalytics/Swift/index.html'
s.license = 'Apache License, Version 2.0'
s.authors = { 'IBM Bluemix Services Mobile SDK' => '[email protected]' }

s.source = { :git => 'https://github.com/ibm-bluemix-mobile-services/bms-clientsdk-swift-analytics.git', :tag => s.version }
s.source_files = 'Source/**/*.swift'
s.ios.exclude_files = 'Source/**/*watchOS*.swift'
s.watchos.exclude_files = 'Source/**/*iOS*.swift'

s.subspec 'SSZipArchive' do |ss|
ss.source_files = 'Source/SSZipArchive/*.{m,h}', 'Source/SSZipArchive/minizip/*.{c,h}', 'Source/SSZipArchive/minizip/aes/*.{c,h}'
ss.libraries = 'z'
ss.pod_target_xcconfig = {'SWIFT_INCLUDE_PATHS' => '$(SRCROOT)/Source/SSZipArchive','LIBRARY_SEARCH_PATHS' => '$(SRCROOT)/Source/SSZipArchive'}
ss.public_header_files= 'Source/SSZipArchive/*.h'
end

s.source_files = 'Source/**/*.swift','Source/Resource/*.h'
s.ios.exclude_files = 'Source/**/*watchOS*.swift'
s.watchos.exclude_files = 'Source/**/*iOS*.swift','Source/Feedback','Source/SSZipArchive/*.{swift,h}', 'Source/SSZipArchive/minizip/*.{c,h}', 'Source/SSZipArchive/minizip/aes/*.{c,h}'
s.dependency 'BMSCore', '~> 2.1'

s.requires_arc = true

s.ios.resources = ['Source/Resources/*.{storyboard,xcassets,json,imageset,png}']
s.ios.deployment_target = '8.0'
s.watchos.deployment_target = '2.0'

end
220 changes: 218 additions & 2 deletions BMSAnalytics.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Pods/BMSAnalyticsAPI/Source/RequestMetadata.swift

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ For apps built with Swift 2.3, use the command `carthage update --toolchain com.
* [Log some other information](#log-some-other-information)
* [Send the data to the server](#send-the-data-to-the-server)
* [Disable logging output](#disable-logging-output-for-production-applications)
* [In app feedback mode](#in-app-feedback-mode)

> View the complete API reference [here](https://ibm-bluemix-mobile-services.github.io/API-docs/client-SDK/BMSAnalytics/Swift/index.html).
Expand Down Expand Up @@ -208,6 +209,16 @@ Analytics.send(completionHandler: { (response: Response?, error: Error?) in

By default, the Logger class will print its logs to Xcode console. If is advised to disable Logger output for applications built in release mode. In order to do so add a debug flag named `RELEASE_BUILD` to your release build configuration. One way of doing so is adding `-D RELEASE_BUILD` to the `Other Swift Flags` section of the project build configuration.

--

### In app feedback mode

Users and Testers can record and send feedback and bug reports 'In-app', as they run and use the application. App owners get a deeper sense of the application's user experience with this context rich user feedback. Developers on the other hand receive accurate application contexts to diagnose and fix bugs / feature deficiencies.

Applications can invoke feedback mode on any application event such as buttons, menu actions or gestures on calling the method:

```Analytics.triggerFeedbackMode()```

--------

## License
Expand Down
8 changes: 7 additions & 1 deletion Source/Analytics/BMSAnalytics+iOS.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,13 @@ public extension BMSAnalytics {

return (osVersion, model, deviceId)
}


// Set uiviewcontroller from cordova applications
public static var callersUIViewController: UIViewController?
public static func setCallersUIViewController( uiViewController: UIViewController) -> Void {
callersUIViewController = uiViewController
}

}


Expand Down
19 changes: 18 additions & 1 deletion Source/Analytics/BMSAnalytics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ public extension Analytics {
else {
Analytics.logger.warn(message: "Make sure that the BMSClient class has been initialized before calling the Analytics initializer.")
}

// Send Feedback data
#if os(iOS)
Feedback.send(fromSentButton: false)
#endif
}


Expand All @@ -119,7 +124,19 @@ public extension Analytics {

Logger.sendAnalytics(completionHandler: userCallback)
}


/**
Trigger feedback Mode

Note: Feedback Mode can only be triggered if the BMSClient was initialized with `BMSClient.sharedInstance.initialize(bluemixRegion:)` from the `BMSCore` framework.
*/
public static func triggerFeedbackMode() {
#if os(iOS)
Feedback.invokeFeedback()
#else
Analytics.logger.warn(message: "Feedback Mode cannot be invoked for non-iOS apps.")
#endif
}
}


Expand Down
1 change: 1 addition & 0 deletions Source/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ internal struct Constants {

static let hostName = "mobile-analytics-dashboard"
static let uploadPath = "/analytics-service/rest/data/events/clientlogs/"
static let uploadFeedbackPath = "/analytics-service/rest/data/events/inappfeedback/"
}


Expand Down
139 changes: 139 additions & 0 deletions Source/Feedback/ComposeEditorViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
/*
*     Copyright 2016 IBM Corp.
*     Licensed under the Apache License, Version 2.0 (the "License");
*     you may not use this file except in compliance with the License.
*     You may obtain a copy of the License at
*     http://www.apache.org/licenses/LICENSE-2.0
*     Unless required by applicable law or agreed to in writing, software
*     distributed under the License is distributed on an "AS IS" BASIS,
*     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*     See the License for the specific language governing permissions and
*     limitations under the License.
*/



// MARK: - Swift 3

#if swift(>=3.0)

import UIKit

class ComposeEditorViewController: UIViewController {

var messages: [String] = [String]()

override func viewDidLoad() {
super.viewDidLoad()
// messageBox.delegate = self as! UITextViewDelegate

// Do any additional setup after loading the view.
messageBox.placeholder = "Please enter your comments here"
messageBox.textColor = UIColor.lightGray

self.messageBox.textContainer.maximumNumberOfLines = 5
self.messageBox.textContainer.lineBreakMode = .byTruncatingTail

messageBox.inputView = UIView()

messageBox.translatesAutoresizingMaskIntoConstraints = false
messageBox.isScrollEnabled = false

func textViewDidChange(_ textView: UITextView) {
let fixedWidth = messageBox.frame.size.width
messageBox.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
let newSize = messageBox.sizeThatFits(CGSize(width: fixedWidth, height: CGFloat.greatestFiniteMagnitude))
var newFrame = messageBox.frame
newFrame.size = CGSize(width: max(newSize.width, fixedWidth), height: newSize.height)
messageBox.frame = newFrame
}

}

@IBOutlet weak var messageBox: UITextView!

@IBAction func messagePopupOK(_ sender: Any) {

Feedback.messages.append(messageBox.text)

dismiss(animated: false, completion: nil)
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}

}

extension UITextView: UITextViewDelegate {

/// Resize the placeholder when the UITextView bounds change
override open var bounds: CGRect {
didSet {
self.resizePlaceholder()
}
}

/// The UITextView placeholder text
public var placeholder: String? {
get {
var placeholderText: String?

if let placeholderLabel = self.viewWithTag(100) as? UILabel {
placeholderText = placeholderLabel.text
}

return placeholderText
}
set {
if let placeholderLabel = self.viewWithTag(100) as? UILabel {
placeholderLabel.text = newValue
placeholderLabel.sizeToFit()
} else {
self.addPlaceholder(newValue!)
}
}
}

/// When the UITextView did change, show or hide the label based on if the UITextView is empty or not
///
/// - Parameter textView: The UITextView that got updated
public func textViewDidChange(_ textView: UITextView) {
if let placeholderLabel = self.viewWithTag(100) as? UILabel {
placeholderLabel.isHidden = self.text.characters.count > 0
}
}

/// Resize the placeholder UILabel to make sure it's in the same position as the UITextView text
private func resizePlaceholder() {
if let placeholderLabel = self.viewWithTag(100) as! UILabel? {
let labelX = self.textContainer.lineFragmentPadding
let labelY = self.textContainerInset.top - 2
let labelWidth = self.frame.width - (labelX * 2)
let labelHeight = placeholderLabel.frame.height

placeholderLabel.frame = CGRect(x: labelX, y: labelY, width: labelWidth, height: labelHeight)
}
}

/// Adds a placeholder UILabel to this UITextView
private func addPlaceholder(_ placeholderText: String) {
let placeholderLabel = UILabel()

placeholderLabel.text = placeholderText
placeholderLabel.sizeToFit()

placeholderLabel.font = self.font
placeholderLabel.textColor = UIColor.lightGray
placeholderLabel.tag = 100

placeholderLabel.isHidden = self.text.characters.count > 0

self.addSubview(placeholderLabel)
self.resizePlaceholder()
self.delegate = self
}

}

#endif
Loading

0 comments on commit 370475c

Please sign in to comment.