alexisakers / bulletinboard Goto Github PK
View Code? Open in Web Editor NEWGeneral-purpose contextual cards for iOS
License: MIT License
General-purpose contextual cards for iOS
License: MIT License
If the bulletin is not dismissible, but you move the card to the iPhone safe area, it will not reset to the proper position.
Hi, when I print text in textInputHandler, it print twice in console log! what should I do ?
page.textInputHandler = { (item, text) in
print("value is (text)")
}
Hi! When is the new release?
Align Custom Views Using Contraint
I am using this library https://github.com/evgenyneu/Cosmos and I want to display it below the title, basically I am trying to achieve something similar to below screen (ignore the close icon)
I created a custom page item class extending BulletinItem for this purpose
open class ReviewBulletinItem: BulletinItem {
public weak var manager: BulletinManager?
public var isDismissable: Bool = true
public var dismissalHandler: ((BulletinItem) -> Void)?
public var nextItem: BulletinItem?
private let title: String = "ADD REVIEW"
private let grade: Double = 3.6
public func makeArrangedSubviews() -> [UIView] {
// Init Sub Views
var arrangedSubviews = [UIView]()
let titleLabel: UILabel = self.makeTitleLabel(reading: self.title)
let starRating: CosmosView = self.makeStarRating(withGrade: self.grade)
// Add Sub Views
for subView in [titleLabel, starRating] {
arrangedSubviews.append(subView)
}
return arrangedSubviews
}
private func makeTitleLabel(reading title: String) -> UILabel {
let titleLabel = UILabel()
titleLabel.textAlignment = .center
titleLabel.textColor = UIColor(hex: "#000000")
titleLabel.accessibilityTraits |= UIAccessibilityTraitHeader
titleLabel.numberOfLines = 1
titleLabel.adjustsFontSizeToFitWidth = true
titleLabel.font = UIFontLocalized(englishFontSize: 18.0, arabicFontSize: 18.0)
titleLabel.text = title.uppercased()
return titleLabel
}
private func makeStarRating(withGrade grade: Double) -> CosmosView {
let ratingView = CosmosView()
ratingView.backgroundColor = .red
ratingView.rating = grade
ratingView.settings.starSize = 18.0
ratingView.settings.starMargin = 2.0
ratingView.settings.fillMode = .precise
ratingView.settings.filledImage = UIImage(named: "palm-tree-full")
ratingView.settings.emptyImage = UIImage(named: "palm-tree-empty")
ratingView.translatesAutoresizingMaskIntoConstraints = false
ratingView.widthAnchor.constraint(equalToConstant: 128).isActive = true
return ratingView
}
public func tearDown() {
print("tearDown")
}
}
The issue is, the star rating takes the full width screen and align left of the screen, whereas I want it in the center. PFA the screnshot
How do we align this view to the center? I tried applying constraints to ratingView and it does not seem to work.
Itunes Connect issue when releasing on App Store
Hi Alex,
I've got an issue with the library when I'm uploading my app on the app store.
This is the message I receive:
Dear developer,
We have discovered one or more issues with your recent delivery for "****". To process your delivery, the following issues must be corrected:
Invalid Bundle - Disallowed LLVM instrumentation. Do not submit apps with LLVM profiling instrumentation or coverage collection enabled. Turn off LLVM profiling or code coverage, rebuild your app and resubmit the app.
Once these issues have been corrected, you can then redeliver the corrected binary.
Regards,
The App Store team
I'm not using the latest bulletin board,
as you've changed the implementation of some functions and renaming some file,
I'm not able to upgrade to the latest version yet
Thank you!
@alexaubry BulletinBoard is still not working on 3.2, I still get the same errors as I described on Twitter.
Furthermore, see the screenshot of Issue Navigator.
Thanks
So if I wanted to display two different pages which are not related to each other and should be displayed at different times would I need to create two bulletin managers? The thing is that I could only use one manager but then I'd have to hide the first page very quickly to show the nextPage
.
Hey guys, thanks for this beautiful lib,
Is there a way to easely manage the blurring of the covered view ?
thanks
It would be great if we could have the contentView exposed, something like this inside the BulletinManager class:
public func getContentView() -> UIView {
return viewController.contentView
}
For my use case, this would be to add some UIMotionEffects to the contentView. Rather than making this part of the lib, it would be better to just simply expose the contentView so devs can handle such customisations themselves.
I can make a PR if you're happy with this change (or feel free to add it yourself in your next commit).
I'm unable to present any view controller above the BulletinBoard. In the past version, there used to be the presentAboveBulletin() function in BulletinManager. However, it is not available anymore.
this is my viewDidLoad() function:
override func viewDidLoad() {
super.viewDidLoad()
bulletinManager.prepare()
bulletinManager.presentBulletin(above: self)
// Do any additional setup after loading the view, typically from a nib.
}
on running the app the bulletin is not displayed.
error shown is:
2018-05-12 22:49:55.789917+0530 Bullet[1796:709739] Warning: Attempt to present <BulletinBoard.BulletinViewController: 0x103312770> on <Bullet.ViewController: 0x10330c810> whose view is not in the window hierarchy!
however the bulletin is presented through an IBAction button press successfully
In the README it is stated that this library supports NFC tags. I'm getting an error from iTunes Connect saying that I need to specify that since I am using NSBluetoothPeripheralUsageDescription
inside my app I have to specify the reason in the .plist file. Now, the issue is that I am not using NFC/Bluetooth. What I did was installing the pod plus duplicating every file in the example project.
Do you think this issue is in some way related to this library? (It's one of the few libraries I am using) โย is there also any way to disable NFC tagging? Thanks!
I have an issue with custom BulletinItems, if any contain UITextFields, it is impossible for a user on a physical device to provide input and see what they are typing. I have created a work around, however, I think it would be best to have an implemented feature for this.
I am not super familiar with swift conventions or best practices, but here is my current work around (function in BullitenManager.swift):
public func moveView(position: CGFloat) {
if position != 0 {
self.viewController.view.frame.origin.y -= position
} else {
self.viewController.view.frame.origin.y = 0
}
}
I can make a fork and PR but I just saw a new version was being worked on and I am unsure of your workflow. Any help/feedback would be greatly appreciated!
Hello,
When using carthage update, we don't seem to receive the latest version, and the bulletins don't move with the keyboard.
Do you need to update something to make Carthage reference the latest version?
Thanks
Is it possible to put textfield instead of button ?
I would like to request support for a property called attributedDescriptionText
in addition to descriptionText
. The level of effort to add it should be pretty minimal, and it would allow for more customization in the appearance of the text, making the library more flexible to handle other use cases.
I've run into a situation that seems like it would be a good match for this, and would love to see support added.
The hard work is appreciated, and thank you for your consideration!
For my app, I wanted to customize the stock PageBulletinItem class with additional views so that we have a consistent look and feel between stock and modified Pages. Unfortunately, some parts of PageBulletinItem are public instead of open and can't be overridden, and the stack view of buttons is not available outside of makeArrangedSubviews().
Do you have any interest in exposing additional customization, and/or would you accept a PR for such a feature? I think it could be done cleanly with either additional function variables (like actionHandler), optional protocol funcs, or override-able funcs in PageBulletinItem. These customization points would be called inside PageBulletinItem.makeArrangedSubviews(). Example:
open func viewsAboveTitle(_ interfaceBuilder: BulletinInterfaceBuilder) -> [UIView]
and so on for the "space" before and after each element: | title | image | description | buttons |
Here's an example I made with a local copy of PageBulletinItem.
class TextFieldPageBulletinItem: CustomizedPageBulletinItem {
fileprivate var errorLabel: UILabel?
fileprivate var textField: UITextField?
public var textInputHandler: ((_ text: String) -> Void)?
override func makeArrangedSubviews() -> [UIView] {
var arrangedSubviews = super.makeArrangedSubviews()
let interfaceBuilder = InterfaceBuilderType.init(appearance: appearance)
errorLabel = interfaceBuilder.makeDescriptionLabel()
errorLabel!.text = ""
errorLabel!.textColor = .red
textField = UITextField()
textField!.delegate = self
textField!.borderStyle = .roundedRect
textField!.returnKeyType = .done
// find the optional stack view of buttons and insert above it
var buttonStack: UIStackView?
for view in arrangedSubviews {
if let bs = view as? UIStackView {
buttonStack = bs
break
}
}
if let buttonStack = buttonStack, let idx = arrangedSubviews.index(of: buttonStack) {
// insert in reverse order
arrangedSubviews.insert(textField!, at: idx)
arrangedSubviews.insert(errorLabel!, at: idx)
} else {
// insert in correct order
arrangedSubviews.append(errorLabel!)
arrangedSubviews.append(textField!)
}
// since there isn't a method similar to "viewDidAppear" for BulletinItems,
// we're using a workaround open the keyboard after a certain amount of time has elapsed
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
self?.textField?.becomeFirstResponder()
}
return arrangedSubviews
}
}
extension TextFieldPageBulletinItem: UITextFieldDelegate {
func isInputValid(text: String?) -> Bool {
if text != nil && !text!.isEmpty {
return true
}
return false
}
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
if let text = textField.text, isInputValid(text: text) {
textField.resignFirstResponder()
textInputHandler?(text)
return true
} else {
errorLabel?.text = "You must enter some text to continue."
textField.backgroundColor = .red
return false
}
}
}
I was wondering if it is possible to support a collection view within in the bulletin page? For example, have a horizontal scrolling collection view that represents a list of images. Is this possible?
Thanks!
iPhone 7 iOS 11.2:
iPhone 8 Plus iOS 11.2:
I do not think the condition failed even when it's not iPhone X that doesn't have rounded corners. Because in iOS 11 they are all under safe area so screenHasRoundedCorners
will always be true in iOS 11+
@available(iOS 11.0, *)
fileprivate var screenHasRoundedCorners: Bool {
let insets = view.safeAreaInsets
return (insets.top > 0) || (insets.bottom > 0)
}
seems to fix the problem, I'm working on a commit
I would like to be able to interact with my bulletin pages after they are shown to the user. For example: setting the first responder in order to show the keyboard, or disabling a button until a user has taken some other action. Right now it is only possible to do this via asyncAfter or a timer.
I know that it is possible to pass a completion block to BulletinManager.presentBulletin(), but it does not have easy access to a bulletin's internal members.
What do you think about adding an override-able method to BulletinIem that is called from BulletinManager.refreshCurrentItemInterface()? I'm not sure whether it would be better to call before the "Animate transition" or added to the transitionAnimationChain, but either one would be a good start.
just comment out of BulletinSwipeInteractionController.swif line 45 prepareGestureRecognizer()
, though pan action cannot be usable.
I just choose background style in example from Dimmed (Default) to any another and after the board shows, i push button "Configure", app will crash here.
Update:
Same crash, when i just complete first intro (in every launch), and pushed "Show intro" again.
Hello! I think it's better to replace this:
( on presentBulletin func on BulletinManager )
presentingVC.present(viewController, animated: animated, completion: completion)
with:
if let tabBar = presentingVC.tabBarController { tabBar.present(viewController, animated: animated, completion: completion) }else{ presentingVC.present(viewController, animated: animated, completion: completion) }
Like this, if the tabBar is present, it shows over it.
Thank you
When setting isDismissable to true this should enable tapping the background to dismiss the bulletin item. However, currently this also allows the content view to also be tapped which could be done accedentily by the user if trying to tap other content such as buttons.
After setting isDismissable to TRUE, tapping on either the background or on the content view, the item is dismissed. I sould expect this to only be when tapping the background or dragging the item off the screen as per the code documentation for isDismissable.
I cannot seem to be able to dismiss any page on an iPad, even though the isDismissable
page property is set to true. Kindly check out this GIF: http://www.giphy.com/gifs/xUOwGa67p1p3bKq8Vy. How can I fix this?
Will this library be available for manual installation (not using CocoaPods/Carthage) in the future?
When using Carthage [static frameworks], the linker fails. Simply unchecking Gather Coverage Data
in BulletinBoard's test scheme fixes this issue.
When swiping to dismiss a PageBulletinItem, it dismisses correctly but does not trigger the dismissalHandler. The dismissalHandler works fine with tap to dismiss.
After setting up a simple PageBulletinItem providing a title, descriptiontext, actionbuttontitle, alternativebuttontitle, setting isDismissable to TRUE as well as supplying an actionHandler and dismissalHandler. When presenting this item, tapping to dismiss triggers the dismissalHandler where as swiping does not.
I was eager to try this framework as it looks great. I was able to play around the with example yesterday and decided to install it via Pods into my project. It seems out of date from the Example on GitHub.
Some issues:
Example #1
There is no BulletinBackgroundViewStyle.swift in my installed Pod file
Example #2
In the BuildManager.swift there is no
public ivar public var backgroundViewStyle
I followed the install instructions and have a simple
pod 'BulletinBoard'
[FYI, Instructions should put line in single quotes instead of double quotes]
alongside my other pod files.
I am adding the framework manually in my workspace with the source. The project builds successfully but when I try to run it on the simulator, I get the following error message, possibly due to a namespace collision with a tvOS framework:
dyld: Symbol not found: OBJC_CLASS$_BBAction
Referenced from: /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/VideoSubscriberAccount.framework/VideoSubscriberAccount
Expected in: /Users/gargs/Library/Developer/Xcode/DerivedData/iPhoneApp-gsobcvjpesljtaakzbpampqecelj/Build/Products/Debug-iphonesimulator/BulletinBoard.framework/BulletinBoard
in /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/CoreSimulator/Profiles/Runtimes/iOS.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/VideoSubscriberAccount.framework/VideoSubscriberAccount
The issue occurs when the framework is manually added as a build dependency in a workspace. If I rename the product from 'BulletinBoard' to anything else, I am able to build and run on both device as well as the simulator. I am probably doing something wrong, but would really appreciate help on figuring out what exactly that is.
Hello !
Is not available in the master branch :/
Thank you
The width constraint is changing inbetween the card transitions on older iPads.
When using the bulletin board on an an older iPad, the width constraint is updating when switching cards. This appears to work correctly on newer iPads and on phones using the compact size class.
func finishSignUp() {
let page = PageBulletinItem(title: "Registration Completed")
page.interfaceFactory.tintColor = UIColor.chatumGreen
page.descriptionText = "Happy chatting!"
page.actionButtonTitle = "Get started"
page.actionHandler = { (item: PageBulletinItem) in
print("Action button tapped")
}
let bulletinManager = BulletinManager(rootItem: page)
bulletinManager.prepare()
bulletinManager.presentBulletin(above: self)
}
Action button is never triggered for me.. any advice ?
When activityIndicator
is animating and you are swiping an item, the indicator stays under the activeSnapshotView
. When item is dismissed activityIndicator
is still visible and disappears only after a BulletinViewController
is dismissed.
Also activityIndicator
's isUserInteractionEnabled
property is set to true
, so it cancels UIPanGestureRecognizer
's events. The events can be recognized only in activityIndicator
's margins area.
Hello All,
I don't know if any of you are interested, But I have started work on a port over to react-native!
Is this something you guys would be interested in?
Thanks
When the isDismissable property is set to true you can touch outside of the card to dismiss, but I think you should also be able to swipe the card down with a gesture as well.
Yesterday, I needed to add an activity spinner to one of my bulletin board pages, but I wanted it inline instead of a full page spinner. It is essentially: "Downloading Images" [spinner] [cancel button]
A standard UIView can't be easily added to the contentViews stack because it has no intrinsic content size. If you don't set a frame, it is sized to 0x0. If you do set a frame, it must be manually centered without access to the superview's frame. And you can't use constraints because it hasn't been added to the superview.
This custom UIView (thanks StackOverflow!) solves the problem by forcing an intrinsic size.
// NOTE: only height is honored by the current StackView settings
class IntrinsicSizeView: UIView {
var width: CGFloat = 32.0
var height: CGFloat = 32.0
convenience init(width: CGFloat, height: CGFloat) {
self.init()
self.width = width
self.height = height
}
override var intrinsicContentSize: CGSize {
get {
return CGSize(width: width, height: height)
}
}
}
Now as it turns out, UIActivityIndicatorView does have an intrinsic size, and this wasn't necessary for my particular case. But it may help someone else, and I thought it might be a nice addition to BulletinInterfaceBuilder, e.g. makeFixedSizeView(width, height) could vend a BulletinBoardFixedHeightView or something along those lines.
Something that's necessary for my use of BulletinBoard is the ability to change either button's title and description text after after page item has been displayed, as there is code being done in the background and I'm graying out the action button and changing its title. For some reason, when I try to set a button's title or the description text after it's been displayed, nothing happens. I'm not sure if this was intentional or not, but is there a workaround?
Is there a way to present the activity indicator without the user having to click on a button?
I am trying to make it where as soon as the bulletin is displayed, the activator indicator immediately appears as well.
Here is my source code to help you understand what I am trying to do:
static func submitQuestionnairePage() -> FeedbackPageBulletinItem {
let page = FeedbackPageBulletinItem(title: "Submitting Questionnaire")
page.descriptionText = "Survey complete!"
page.isDismissable = false
page.manager?.displayActivityIndicator()
return page
}
When I run this code the bulletin does not display the loading icon. It only displays the page title and description text.
Hi! In my project I'm using displayActivityIndicator() in order to wait during a sync/download. I would like to avoid that the user can dismiss the download and close the activity indicator.
My idea was to insert self.view.isUserInteractionEnabled = false like the example below. However it doesn't work I can dismiss the item. Any idea ? Thanks a lot in advance!
self.page.actionHandler = { (item: PageBulletinItem) in
item.manager?.displayActivityIndicator()
self.view.isUserInteractionEnabled = false
iControl.ICSes.login(user: "xxxx", pass: "xxx") { (loginStatus) in
switch loginStatus {
case .online:
iControl.ICSes.synchronize { (synchronizeStatus, error) in
if synchronizeStatus {
//Two next lines avoid to have multiple refresh buttons iterations
self.refreshMode.removeFromSuperview()
self.collectionView?.reloadSections(IndexSet(0 ..< 1))
self.collectionView.reloadData()
self.page.nextItem = BulletinDataSource.makeCompletionPage()
item.manager?.displayNextItem()
self.view.isUserInteractionEnabled = true
self.tipView?.dismiss()
self.refreshMode.stop()
} else { NSLog("Error: \(error!.stringValue)") }
}
case .local: break
case .none: break
}
}
}
For appearances, there is no option to change the font of the labels which lacks of the uniform of my currently developing app and I intend to use Avenir Next throughout. This would be a nice feature to add on.
It would be awesome if the PageBulletinItem.interfaceFactory has a property to control the font.
More an improvement here, not an issue.
I installed the library through CocoaPods and then imported it in the viewcontroller as shown in the example:
@import BulletinBoard;
Then when I create the property for BulletinManager
, Xcode will throw an error Unknown type name BulletinManager
.
I installed the library through CocoaPods and then imported it in the viewcontroller as shown in the example:
@import BulletinBoard;
Then when I create the property for BulletinManager
, Xcode will throw an error Unknown type name BulletinManager
.
A date picker ๐๐๐
Looks like when using the PodFile it doesn't contain all of the source.
Missing:
ActionBulletinItem.swift
BulletinAppearance.swift
BulletinInterfaceBuilder.swift
BulletinPadding.swift
AnimationChain.swift
Can't seem to present the next item...
Can't seem to present the next item... Method isn't there when checking files in the Pod.
Hello! Thank you very much for this framework. I call the BulletinManager from my manager, which is called from the Observer. I have a problem, buttons' handlers don't work. Please tell me how it can be fixed? Thanks
class MatchAlertManager {
func present(_ match: MatchPersonalModel) {
guard let topVC = UIApplication.topViewController() else { return }
guard !topVC.isModal() else { return }
let userInfo = match.userInfo
let page = PageBulletinItem(title: "You have a match!")
page.descriptionText = "some text"
page.actionButtonTitle = "Ok"
page.alternativeButtonTitle = "Not now"
// actions
page.actionHandler = { item in
debugPrint("actionHandler")
}
page.alternativeHandler = { item in
item.manager?.dismissBulletin(animated: true)
}
let bulletinManager = BulletinManager(rootItem: page)
bulletinManager.prepare()
if let mainTabBarController = topVC.tabBarController as? MainTabBarController {
bulletinManager.presentBulletin(above: mainTabBarController)
} else {
bulletinManager.presentBulletin(above: topVC)
}
}
}
Hi! I need to hide the status bar of my bulletins (no statusbar on my app). In my BulletinDataSource I added :
var prefersStatusBarHidden: Bool {
get {
return true
}
}
However it doesn't change nothing, status bar appears as soon as the bulletin is displayed. Any idea? Thanks!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.