In order to manage/shorten my code a little, I decided to try to create a helper class to manage all alerts.
The idea is that the helper class will create the alert. When the user presses the button, it will then send a callback to inform the code on the viewController which button is pressed. Then based on that I can fire different bits of code.
Currently the code I have manages to pop up the alert correctly, but I cannot get it to send the callback when the button is pressed.
here is my alert manager I created so far(still basic for simplicity):
var alertMgr: alertManager = alertManager()
class alertManager: NSObject {
func showAlert(titleText:String?, confirmText:String, cancelText:String, msgText:String, showCancel:Bool, showConfirm:Bool, style:UIAlertControllerStyle, viewController:UIViewController) -> Int? {
let alertController = UIAlertController(title: titleText, message: msgText, preferredStyle: style)
var myInt:Int!
let actionLeft = UIAlertAction(title:cancelText, style: .Cancel) { action in
println("0") //works when user presses cancel button
myInt = 0
}
let actionRight = UIAlertAction(title:confirmText, style: .Default) { action in
println("1") //works when user presses confirm button
myInt = 1
}
alertController.addAction(actionLeft)
alertController.addAction(actionRight)
viewController.presentViewController(alertController, animated: true, completion: nil)
return myInt //does not return when button is pressed???
}
}
In my code when I want to show an alert I use the following code:
let titleTxt:String = "title txt goes here."
let confirmTxt:String = "confirm"
let cancelTxt:String = "cancel"
let msgTxt:String = "some msg goes here."
let showCancel:Bool = true
let showConfirm:Bool = true
let style:UIAlertControllerStyle = .ActionSheet
let alert = alertMgr.showAlert(titleTxt, confirmText: confirmTxt, cancelText: cancelTxt, msgText: msgTxt, showCancel: showCancel, showConfirm: showConfirm, style:style, viewController: self)
switch alert as Int! {
case nil:
println("nil value")
case 0:
println("cancel pressed") //never gets fired. when button is pressed
case 1:
println("confirm pressed") //never gets fired. when button is pressed
default:
break
}
The main problem is I cannot seem to get the call back to send the "myInt" value on button press. I have searched through pretty much all questions on here with [UIAlertController] and have not been able to find any hints that would push me in the right direction.
Any help would be great.
showAlert returns the value of myInt before any of the given blocks gets a chance to be executed, the solution is to pass complete action-blocks as parameters of showAlert. In order to shorten the signature you can prepare a special type with text, block and flag values and make the function to process arrays of the objects of this type.
Related
I have been having problems splitting my Typescript file into 2 separate Typescript files (with one imported into the other).
When the files aren't separated, my web app runs perfectly fine, but when I separate them, I get an Uncaught ReferenceError for an initialisation function in my main Typescript file.
The start of the main Typescript file is as follows:
import { Ticket } from "./Ticket";
// Constant Declarations
const arrCategory: string[] = ["Billing", "Marketing", "Developing"];
const arrPriority: string[] = ["Low", "Medium", "High"];
const arrStatus: string[] = ["Open", "Solved", "Closed"];
// Variable Declarations
// Form Inputs
let labelSearch: HTMLElement = (<HTMLElement>document.getElementById("search-label"));
let inputSearchList: HTMLInputElement = (<HTMLInputElement>document.getElementById("search-list"));
let inputIdentifier: HTMLInputElement = (<HTMLInputElement>document.getElementById("ticket-identifier"));
let inputSubject: HTMLInputElement = (<HTMLInputElement>document.getElementById("ticket-subject"));
let inputCategory: HTMLInputElement = (<HTMLInputElement>document.getElementById("ticket-category"));
let inputAssignee: HTMLInputElement = (<HTMLInputElement>document.getElementById("ticket-assignee"));
let inputPriority: HTMLInputElement = (<HTMLInputElement>document.getElementById("ticket-priority"));
let inputStatus: HTMLInputElement = (<HTMLInputElement>document.getElementById("ticket-status"));
let inputComments: HTMLInputElement = (<HTMLInputElement>document.getElementById("ticket-comments"));
let buttonSubmit: HTMLInputElement = (<HTMLInputElement>document.getElementById("submit"));
let buttonReset: HTMLInputElement = (<HTMLInputElement>document.getElementById("reset"));
let message: HTMLElement = (<HTMLElement>document.getElementById("message"));
// Database of Ticket Objects
let arrTickets: Ticket[] = [];
let activeTicket: Ticket; // The active ticket in the form (if editing/deleting)
let ticket1: Ticket;
let ticket2: Ticket;
let ticket3: Ticket;
let ticket4: Ticket;
let ticket5: Ticket;
let ticket6: Ticket;
let ticket7: Ticket;
let ticket8: Ticket;
let ticket9: Ticket;
let ticket10: Ticket;
/**
* initialiseDatabase prepares a predefined set of 10 records in the database.
* Is called onload after the HTML is loaded and also calls the initialiseForm function.
*/
function initialiseDatabase(): void {
// Initialise database with 10 records
ticket1 = new Ticket("Rec001", "Submit Button Bug", arrCategory[2], "Matthew Martin",
arrPriority[2], arrStatus[1], "Submit button doesn't save ticket information.");
arrTickets.push(ticket1);
ticket2 = new Ticket("Rec002", "Payment Information Error", arrCategory[0], "Lisa Kim",
arrPriority[2], arrStatus[0], "Error whenever I try to enter my payment information.");
arrTickets.push(ticket2);
ticket3 = new Ticket("Rec003", "No Advertisements", arrCategory[1], "Fidel Badiola",
arrPriority[0], arrStatus[2], "Not receiving advertisements even though I am signed up.");
arrTickets.push(ticket3);
ticket4 = new Ticket("Rec004", "Output Message Timing", arrCategory[2], "Aaron Parry",
arrPriority[1], arrStatus[0], "Sometimes the output message disappears immediately.");
arrTickets.push(ticket4);
ticket5 = new Ticket("Rec005", "Save Card Information", arrCategory[0], "Anthony George",
arrPriority[0], arrStatus[0], "");
arrTickets.push(ticket5);
ticket6 = new Ticket("Rec006", "Edit Form", arrCategory[2], "Stephanie Lea",
arrPriority[0], arrStatus[2], "A reset button on the edit form would be especially useful.");
arrTickets.push(ticket6);
ticket7 = new Ticket("Rec007", "Spelling Mistake", arrCategory[1], "Tonia Martin",
arrPriority[0], arrStatus[0], "There is a spelling mistake on the edit page.");
arrTickets.push(ticket7);
ticket8 = new Ticket("Rec008", "Card Denied", arrCategory[0], "David Kim",
arrPriority[1], arrStatus[2], "Some bank cards are automatically denied.");
arrTickets.push(ticket8);
ticket9 = new Ticket("Rec009", "Save Card Function?", arrCategory[0], "Matthew Martin",
arrPriority[0], arrStatus[0], "");
arrTickets.push(ticket9);
ticket10 = new Ticket("Rec010", "Form Scaling", arrCategory[0], "Lisa Kim",
arrPriority[1], arrStatus[1], "The form doesn't scale properly at low window widths.");
arrTickets.push(ticket10);
// Prepare the form
initialiseForm();
}
The import Ticket class code is fairly simple, but I'd like to be able to separate it from the main Typescript file.
My HTML code is as follows:
<head>
<script data-main="src/TicketApp.js" src="src/require.js"></script>
</head>
<body>
</body>
<script>
require(['domReady!', 'TicketApp'], function(domReady) {
initialiseDatabase();
});
</script>
When I try to load the web app, I get the following error:
Uncaught ReferenceError: initialiseDatabase is not defined
I'm bewildered as to why I only get this error when I separate the Ticket class from the main Typescript file.
I've only just started learning RequireJS so there may be some problems with my syntax, except I get no errors when there is only 1 Typescript file, so I'm having a lot of trouble working out where the problem might be.
In our tvOS app we have a customised tabbar. now additionally we want to change the background color of the focused/selected item. When I do by tabBarAppearance.selectionIndicatorTintColor = .purple, it changes focused and selected states to purple(while without that line code we do have different colors or at least different opacities).
no custom color focused:
no custom color selected
custom color focused
custom color selected
Is it possible to use different colors for focused and selected (like I did for the item text, as you can see on the screen shots)?
I fixed that by setting the the standardAppearance of the tab bar each time the focus changes in my UITabBarController. The relevant code looks like this (the initial setup of appearance is only posted for completeness):
// setting up standard appearance for the first time
private func setupTabbarAppearance() {
let tabBarAppearance = UITabBarAppearance()
//...
tabBarAppearance.selectionIndicatorTintColor = .focusedBackgroundColor // focused items
//...
let itemAppearance = UITabBarItemAppearance()
//...
itemAppearance.normal.titleTextAttributes[.foregroundColor] = .normalTextColor // used for focused AND non-focused items,
// when the whole tabbar is focused
//...
itemAppearance.selected.titleTextAttributes[.foregroundColor] = .selectedTextColor // used for the selected item,
// wen tabbar is not focused
// ...
tabBarAppearance.inlineLayoutAppearance = itemAppearance
tabBar.standardAppearance = tabBarAppearance
tabBar.setNeedsLayout()
}
private func setTabBarIndicatorColor(tabBarFocused: Bool) {
let currentAppearance = tabBar.standardAppearance
// here is where the color is set
currentAppearance.selectionIndicatorTintColor = tabBarFocused ? .focusedBackgroundColor : .selectedBackgroundColor
tabBar.standardAppearance = currentAppearance
}
// change appearance each time, when focus changes in tabbar controller
override func didUpdateFocus(in context: UIFocusUpdateContext, with coordinator: UIFocusAnimationCoordinator) {
if isTabbarInHierarchy(view: context.nextFocusedView) {
setTabBarIndicatorColor(tabBarFocused: true)
} else {
setTabBarIndicatorColor(tabBarFocused: false)
}
super.didUpdateFocus(in: context, with: coordinator)
}
private func isTabbarInHierarchy(view: UIView?) -> Bool {
guard let view = view else {return false}
if view == tabBar {
return true
}
return isTabbarInHierarchy(view: view.superview)
}
I have a custom UIStoryboardSegue that works as desired in iOS12.*.
One of the destination view controller is a UITabbarController: for each tab, I have a controller embedded in a navigation controller.
Unfortunately, for iOS13.*, this does not work well: the view controller lifecycle is broken, and no call the viewXXXAppear() nor the willTransition() methods are no longer issued.
It looks like makeKeyAndVisible() has no effect?!
See at the bottom how the screen UI is puzzled below without viewWillAppear() being called.
An horrible temporary workaround
I had to pull my hairs but, I have found a fix which I make public (I had to add a navigation controller on the fly).
This messes the vc hierarchy: do you have a better solution?
public class AladdinReplaceRootViewControllerSegue: UIStoryboardSegue {
override public func perform() {
guard let window = UIApplication.shared.delegate?.window as? UIWindow,
let sourceView = source.view,
let destinationView = destination.view else {
super.perform()
return
}
let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height
destinationView.frame = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight)
window.insertSubview(destinationView, aboveSubview: sourceView)
// **My fix**
if #available(iOS 13,*) {
// I introduced an invisible navigation controller starting in iOS13 otherwise, my controller attached to the tabbar thru a navigation, dont work correctly, no viewXAppearis called.
let navigationController = UINavigationController.init(rootViewController: self.destination)
navigationController.isNavigationBarHidden = true
window.rootViewController = navigationController
}
else {
window.rootViewController = self.destination
}
window.makeKeyAndVisible()
}
}
I found a solution thanks to Unbalanced calls to begin/end appearance transitions with custom segue
What happens here is that the creation and attaching of the destination view controller happens twice, and the first one happens too soon.
So what you need to do is:
public class AladdinReplaceRootViewControllerSegue: UIStoryboardSegue {
override public func perform() {
guard let window = UIApplication.shared.delegate?.window as? UIWindow,
let sourceView = source.view,
let destinationView = destination.view else {
super.perform()
return
}
let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height
let mock = createMockView(view: desination.view)
window.insertSubview(mock, aboveSubview: sourceView)
//DO SOME ANIMATION HERE< MIGHT NEED TO DO mock.alpha = 0
//after the animation is done:
window.rootViewController = self.destination
mock.removeFromSuperview()
}
func createMockView(view: UIView) -> UIImageView {
UIGraphicsBeginImageContextWithOptions(view.frame.size, true, UIScreen.main.scale)
view.drawHierarchy(in: view.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return UIImageView(image: image)
}
}
I had a similar problem on iOS 13 when performing a custom storyboard segue that replaces the rootViewController. The original code looked like this:
#interface CustomSegue : UIStoryboardSegue
#end
#implementation CustomSegue
- (void)perform {
AppDelegate* appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
UIViewController *destination = (UIViewController *) self.destinationViewController;
[destination.view removeFromSuperview];
[appDelegate.window addSubview:destination.view];
appDelegate.window.rootViewController = destination;
}
#end
Removing the line [appDelegate.window addSubview:destination]; fixed the problem to me. Apparanently, it was unnecessary to add the new VC's view as a subview to the window. It did the job correctly even after removing that line, and it also fixed the error message "unbalanced calls to begin/end appearance transitions".
I am working on tvOS app .I have a list of videos and before play main video need to play DFP ad with skip functionality.
I have added skip button on the AVPlayerViewController's view and manage focus(move focus skip button to AVPlayerViewController's view). Focus is working fine if i added AVPlayerViewController as a childViewController but in main video play/pause functionality not working.
self.addChildViewController(playerController)
self.view.addSubview(playerController.view)
If i have added AVPlayerViewController as ParentViewController then focus is not working.
self.view.addSubview(playerController.view)
playerController.didMoveToParentViewController(self)
I have implemented blow code
let playerController = AVPlayerViewController()
var playerObj:AVPlayer!
var asset:AVAsset!
var playerItem:AVPlayerItem!
override func viewDidLoad() {
super.viewDidLoad()
playerController.view.frame = CGRectMake(0.0, 0.0, UIScreen.mainScreen().bounds.width, UIScreen.mainScreen().bounds.height)
self.addChildViewController(playerController)
self.view.addSubview(playerController.view)
self.preferredFocusedView
self.updateFocusIfNeeded()
}
func playVideo(videoURL:String) {
self.playerController.showsPlaybackControls = false
self.asset = AVAsset(URL: NSURL(string: videoURL)!) as AVAsset
self.playerItem = AVPlayerItem(asset: self.asset)
self.playerObj = AVPlayer(playerItem: self.playerItem)
self.playerController.player = self.playerObj
self.playerItem.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions.New, context: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(VideoPlayerViewController.playerItemDidReachEnd(_:)), name: AVPlayerItemDidPlayToEndTimeNotification, object: self.playerObj.currentItem)
if !self.controlFlag{
// For main video
playFlag = true
self.playerController.showsPlaybackControls = true
}else{
// for DFP ad
playFlag = false
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(VideoPlayerViewController.playerStalledNotification(_:)), name: AVPlayerItemPlaybackStalledNotification, object: self.playerObj.currentItem)
}
self.playerController.player!.play()
}
override var preferredFocusedView: UIView? {
get {
if skipAdsButton != nil {
print("focus on skip button")
return self.skipAdsButton
}else{
print("focus on super.preferredFocusedView")
return super.preferredFocusedView
}
}
}
How to fix this issue. Please suggest it.
I'm currently trying to code a minesweeper using scala, but I can't find the way to listen to a right click on a button.
I've already searched on the Internet the way to do it, but I definitely was not able to find it.
If anyone could help me out, I would be really grateful :)
Thanks,
Schnipp
(Note: Scala is a new language to me and I am not a Java user, so I am sorry if my questions sound dumb)
EDIT:
I am trying to find (or implement) a function 'ButtonClickedRight' that could listen to a right-click on a button.
like this
import scala.swing._
import scala._
import scala.swing.event._
object Right extends MainFrame with App {
title = ""
visible = true
val b = new button("")
listenTo(b)
reactions += {
case ButtonClicked(`b`) => *code*
case ButtonClickedRight(`b`) => *code*
}
}
EDIT 2 --
I would like to know if the user has clicked on the Button "1" or not. The problem I have is that this code prints "Mouse clicked at " + e.point+" type "+e.modifiers when I click on the label but not on the button.
object App extends SimpleSwingApplication {
lazy val ui = new GridPanel(2,1) {
contents += new Button("1")
contents += new Label("2")
listenTo(mouse.clicks)
reactions += {
case e: MouseClicked =>
println("Mouse clicked at " + e.point+" type "+e.modifiers)
}
}
def top = new MainFrame {
contents = ui
visible = true
preferredSize = new Dimension(500,500)
}
}
Button events are fired through a specific publisher .mouse.clicks.
import scala.swing._
import scala.swing.event._
object App extends SimpleSwingApplication {
lazy val ui = new GridPanel(2,1) {
val button = new Button("1")
contents += button
contents += new Label("2")
listenTo(button.mouse.clicks) // !
reactions += {
case evt # MouseClicked(`button`, pt, _, _, _) =>
val which = evt.peer.getButton
if (which > 1) {
println(s"Mouse clicked at (${pt.x}; ${pt.y}) - button: $which")
}
}
}
lazy val top = new MainFrame {
contents = ui
size = new Dimension(500,500)
}
}
Note that at least on Linux my right button has number 3 not 2. You could also use the triggersPopup flag, but then you must ensure to monitor both MousePressed and MouseReleased, as this flag is platform-dependent.
I think that you are on the right path, for my understanding of scala swings I think that the problem is that you are not attaching the listener correctly. For one I would assign the button to a value and call listenTo only on it:
val button = new Button("1")
listenTo(button)
Then, in the reactions, I would write the pattern checking in the event that it comes from the button (probably redundant if you only call listenTo passing the button) and that it has the correct button:
case ButtonClicked(b) if b == button && b.peer.getButton == MouseEvent.BUTTON_2 => ...
So the code you provided in your edit would become:
object App extends SimpleSwingApplication {
lazy val ui = new GridPanel(2,1) {
val button = new Button("1")
contents += button
contents += new Label("2")
listenTo(button)
reactions += {
case evt # MouseClicked(b, pt, _, _, _) if b == button && evt.peer.getButton == java.awt.event.MouseEvent.BUTTON2 =>
println(s"Mouse clicked at (${pt.x}; ${pt.y}) - button: ${evt.peer.getButton}")
}
}
def top = new MainFrame {
contents = ui
visible = true
preferredSize = new Dimension(500,500)
}
}
The following works for me:
new Button {
listenTo(mouse.clicks)
reactions += {
case MouseClicked(_, _, c, _, _) => handleClick(c == 0)
}
}
def handleClick(isLeftClick: Boolean): Unit = {
//
}