Prechádzať zdrojové kódy

Agregadas alertas ToAst de cambio de turno.

Ernesto Blanco Careaga 9 rokov pred
rodič
commit
76b2e0582c

+ 8 - 2
TresEnRaya.xcodeproj/project.pbxproj

@@ -13,6 +13,7 @@
 		D28602781E047A5600027A9C /* intro.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = D28602771E047A5600027A9C /* intro.mp3 */; };
 		D286027A1E047A7700027A9C /* perro.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = D28602791E047A7700027A9C /* perro.mp3 */; };
 		D286027C1E047A8000027A9C /* vaca.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = D286027B1E047A8000027A9C /* vaca.mp3 */; };
+		D2BDF7621E057B900087D3CA /* UIView+Toast.m in Sources */ = {isa = PBXBuildFile; fileRef = D2BDF7611E057B900087D3CA /* UIView+Toast.m */; };
 		D2D27AA81DF9BADF004D2378 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = D2D27AA71DF9BADF004D2378 /* main.m */; };
 		D2D27AAB1DF9BADF004D2378 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = D2D27AAA1DF9BADF004D2378 /* AppDelegate.m */; };
 		D2D27AAE1DF9BADF004D2378 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D2D27AAD1DF9BADF004D2378 /* ViewController.m */; };
@@ -29,11 +30,13 @@
 		D28602771E047A5600027A9C /* intro.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = intro.mp3; sourceTree = "<group>"; };
 		D28602791E047A7700027A9C /* perro.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = perro.mp3; sourceTree = "<group>"; };
 		D286027B1E047A8000027A9C /* vaca.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = vaca.mp3; sourceTree = "<group>"; };
+		D2BDF7601E057B900087D3CA /* UIView+Toast.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+Toast.h"; sourceTree = "<group>"; };
+		D2BDF7611E057B900087D3CA /* UIView+Toast.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+Toast.m"; sourceTree = "<group>"; };
 		D2D27AA31DF9BADF004D2378 /* TresEnRaya.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TresEnRaya.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		D2D27AA71DF9BADF004D2378 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
 		D2D27AA91DF9BADF004D2378 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
 		D2D27AAA1DF9BADF004D2378 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
-		D2D27AAC1DF9BADF004D2378 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = text; path = "\U001b\U001b\U001bViewController.h\U001b"; sourceTree = "<group>"; };
+		D2D27AAC1DF9BADF004D2378 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
 		D2D27AAD1DF9BADF004D2378 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
 		D2D27AB01DF9BADF004D2378 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
 		D2D27AB21DF9BADF004D2378 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -73,6 +76,8 @@
 		D2D27AA51DF9BADF004D2378 /* TresEnRaya */ = {
 			isa = PBXGroup;
 			children = (
+				D2BDF7601E057B900087D3CA /* UIView+Toast.h */,
+				D2BDF7611E057B900087D3CA /* UIView+Toast.m */,
 				D2D27AA91DF9BADF004D2378 /* AppDelegate.h */,
 				D28602731E047A0200027A9C /* aplausos.mp3 */,
 				D28602711E0479F600027A9C /* abucheo.mp3 */,
@@ -83,7 +88,7 @@
 				D2D27AAA1DF9BADF004D2378 /* AppDelegate.m */,
 				D2F279E21E046C2D001C5152 /* SoundManager.h */,
 				D2F279E31E046C59001C5152 /* SoundManager.m */,
-				D2D27AAC1DF9BADF004D2378 /* ViewController.h */,
+				D2D27AAC1DF9BADF004D2378 /* ViewController.h */,
 				D2D27AAD1DF9BADF004D2378 /* ViewController.m */,
 				D2D27AAF1DF9BADF004D2378 /* Main.storyboard */,
 				D2D27AB21DF9BADF004D2378 /* Assets.xcassets */,
@@ -183,6 +188,7 @@
 				D2D27AAE1DF9BADF004D2378 /* ViewController.m in Sources */,
 				D2F279E41E046C59001C5152 /* SoundManager.m in Sources */,
 				D2D27AAB1DF9BADF004D2378 /* AppDelegate.m in Sources */,
+				D2BDF7621E057B900087D3CA /* UIView+Toast.m in Sources */,
 				D2D27AA81DF9BADF004D2378 /* main.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;

BIN
TresEnRaya.xcodeproj/project.xcworkspace/xcuserdata/ernestoblancocareaga.xcuserdatad/UserInterfaceState.xcuserstate


BIN
TresEnRaya/.DS_Store


+ 427 - 0
TresEnRaya/UIView+Toast.h

@@ -0,0 +1,427 @@
+//
+//  UIView+Toast.h
+//  Toast
+//
+//  Copyright (c) 2011-2016 Charles Scalesse.
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a
+//  copy of this software and associated documentation files (the
+//  "Software"), to deal in the Software without restriction, including
+//  without limitation the rights to use, copy, modify, merge, publish,
+//  distribute, sublicense, and/or sell copies of the Software, and to
+//  permit persons to whom the Software is furnished to do so, subject to
+//  the following conditions:
+//
+//  The above copyright notice and this permission notice shall be included
+//  in all copies or substantial portions of the Software.
+//
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+//  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+//  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+//  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+//  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+//  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+//  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+#import <UIKit/UIKit.h>
+
+extern const NSString * CSToastPositionTop;
+extern const NSString * CSToastPositionCenter;
+extern const NSString * CSToastPositionBottom;
+
+@class CSToastStyle;
+
+/**
+ Toast is an Objective-C category that adds toast notifications to the UIView
+ object class. It is intended to be simple, lightweight, and easy to use. Most
+ toast notifications can be triggered with a single line of code.
+ 
+ The `makeToast:` methods create a new view and then display it as toast.
+ 
+ The `showToast:` methods display any view as toast.
+ 
+ */
+@interface UIView (Toast)
+
+/**
+ Creates and presents a new toast view with a message and displays it with the
+ default duration and position. Styled using the shared style.
+ 
+ @param message The message to be displayed
+ */
+- (void)makeToast:(NSString *)message;
+
+/**
+ Creates and presents a new toast view with a message. Duration and position
+ can be set explicitly. Styled using the shared style.
+ 
+ @param message The message to be displayed
+ @param duration The toast duration
+ @param position The toast's center point. Can be one of the predefined CSToastPosition
+                 constants or a `CGPoint` wrapped in an `NSValue` object.
+ */
+- (void)makeToast:(NSString *)message
+         duration:(NSTimeInterval)duration
+         position:(id)position;
+
+/**
+ Creates and presents a new toast view with a message. Duration, position, and
+ style can be set explicitly.
+ 
+ @param message The message to be displayed
+ @param duration The toast duration
+ @param position The toast's center point. Can be one of the predefined CSToastPosition
+ constants or a `CGPoint` wrapped in an `NSValue` object.
+ @param style The style. The shared style will be used when nil
+ */
+- (void)makeToast:(NSString *)message
+         duration:(NSTimeInterval)duration
+         position:(id)position
+            style:(CSToastStyle *)style;
+
+/**
+ Creates and presents a new toast view with a message, title, and image. Duration,
+ position, and style can be set explicitly. The completion block executes when the
+ toast view completes. `didTap` will be `YES` if the toast view was dismissed from 
+ a tap.
+ 
+ @param message The message to be displayed
+ @param duration The toast duration
+ @param position The toast's center point. Can be one of the predefined CSToastPosition
+                 constants or a `CGPoint` wrapped in an `NSValue` object.
+ @param title The title
+ @param image The image
+ @param style The style. The shared style will be used when nil
+ @param completion The completion block, executed after the toast view disappears.
+                   didTap will be `YES` if the toast view was dismissed from a tap.
+ */
+- (void)makeToast:(NSString *)message
+         duration:(NSTimeInterval)duration
+         position:(id)position
+            title:(NSString *)title
+            image:(UIImage *)image
+            style:(CSToastStyle *)style
+       completion:(void(^)(BOOL didTap))completion;
+
+/**
+ Creates a new toast view with any combination of message, title, and image.
+ The look and feel is configured via the style. Unlike the `makeToast:` methods,
+ this method does not present the toast view automatically. One of the showToast:
+ methods must be used to present the resulting view.
+ 
+ @warning if message, title, and image are all nil, this method will return nil.
+ 
+ @param message The message to be displayed
+ @param title The title
+ @param image The image
+ @param style The style. The shared style will be used when nil
+ @return The newly created toast view
+ */
+- (UIView *)toastViewForMessage:(NSString *)message
+                          title:(NSString *)title
+                          image:(UIImage *)image
+                          style:(CSToastStyle *)style;
+
+/**
+ Dismisses all active toast views. Any toast that is currently being displayed on the
+ screen is considered active.
+ 
+ @warning this does not clear toast views that are currently waiting in the queue. The next queued 
+ toast will appear immediately after `hideToasts` completes the dismissal animation.
+ 
+ */
+- (void)hideToasts;
+
+/**
+ Dismisses an active toast view.
+ 
+ @param toast The active toast view to dismiss. Any toast that is currently being displayed
+ on the screen is considered active. 
+ 
+ @warning this does not clear a toast view that is currently waiting in the queue.
+ 
+ */
+- (void)hideToast:(UIView *)toast;
+
+/**
+ Creates and displays a new toast activity indicator view at a specified position.
+ 
+ @warning Only one toast activity indicator view can be presented per superview. Subsequent
+ calls to `makeToastActivity:` will be ignored until hideToastActivity is called.
+ 
+ @warning `makeToastActivity:` works independently of the showToast: methods. Toast activity
+ views can be presented and dismissed while toast views are being displayed. `makeToastActivity:`
+ has no effect on the queueing behavior of the showToast: methods.
+ 
+ @param position The toast's center point. Can be one of the predefined CSToastPosition
+                 constants or a `CGPoint` wrapped in an `NSValue` object.
+ */
+- (void)makeToastActivity:(id)position;
+
+/**
+ Dismisses the active toast activity indicator view.
+ */
+- (void)hideToastActivity;
+
+/**
+ Displays any view as toast using the default duration and position.
+ 
+ @param toast The view to be displayed as toast
+ */
+- (void)showToast:(UIView *)toast;
+
+/**
+ Displays any view as toast at a provided position and duration. The completion block 
+ executes when the toast view completes. `didTap` will be `YES` if the toast view was 
+ dismissed from a tap.
+ 
+ @param toast The view to be displayed as toast
+ @param duration The notification duration
+ @param position The toast's center point. Can be one of the predefined CSToastPosition
+                 constants or a `CGPoint` wrapped in an `NSValue` object.
+ @param completion The completion block, executed after the toast view disappears.
+                   didTap will be `YES` if the toast view was dismissed from a tap.
+ */
+- (void)showToast:(UIView *)toast
+         duration:(NSTimeInterval)duration
+         position:(id)position
+       completion:(void(^)(BOOL didTap))completion;
+
+@end
+
+/**
+ `CSToastStyle` instances define the look and feel for toast views created via the 
+ `makeToast:` methods as well for toast views created directly with
+ `toastViewForMessage:title:image:style:`.
+ 
+ @warning `CSToastStyle` offers relatively simple styling options for the default
+ toast view. If you require a toast view with more complex UI, it probably makes more
+ sense to create your own custom UIView subclass and present it with the `showToast:`
+ methods.
+ */
+@interface CSToastStyle : NSObject
+
+/**
+ The background color. Default is `[UIColor blackColor]` at 80% opacity.
+ */
+@property (strong, nonatomic) UIColor *backgroundColor;
+
+/**
+ The title color. Default is `[UIColor whiteColor]`.
+ */
+@property (strong, nonatomic) UIColor *titleColor;
+
+/**
+ The message color. Default is `[UIColor whiteColor]`.
+ */
+@property (strong, nonatomic) UIColor *messageColor;
+
+/**
+ A percentage value from 0.0 to 1.0, representing the maximum width of the toast
+ view relative to it's superview. Default is 0.8 (80% of the superview's width).
+ */
+@property (assign, nonatomic) CGFloat maxWidthPercentage;
+
+/**
+ A percentage value from 0.0 to 1.0, representing the maximum height of the toast
+ view relative to it's superview. Default is 0.8 (80% of the superview's height).
+ */
+@property (assign, nonatomic) CGFloat maxHeightPercentage;
+
+/**
+ The spacing from the horizontal edge of the toast view to the content. When an image
+ is present, this is also used as the padding between the image and the text.
+ Default is 10.0.
+ */
+@property (assign, nonatomic) CGFloat horizontalPadding;
+
+/**
+ The spacing from the vertical edge of the toast view to the content. When a title
+ is present, this is also used as the padding between the title and the message.
+ Default is 10.0.
+ */
+@property (assign, nonatomic) CGFloat verticalPadding;
+
+/**
+ The corner radius. Default is 10.0.
+ */
+@property (assign, nonatomic) CGFloat cornerRadius;
+
+/**
+ The title font. Default is `[UIFont boldSystemFontOfSize:16.0]`.
+ */
+@property (strong, nonatomic) UIFont *titleFont;
+
+/**
+ The message font. Default is `[UIFont systemFontOfSize:16.0]`.
+ */
+@property (strong, nonatomic) UIFont *messageFont;
+
+/**
+ The title text alignment. Default is `NSTextAlignmentLeft`.
+ */
+@property (assign, nonatomic) NSTextAlignment titleAlignment;
+
+/**
+ The message text alignment. Default is `NSTextAlignmentLeft`.
+ */
+@property (assign, nonatomic) NSTextAlignment messageAlignment;
+
+/**
+ The maximum number of lines for the title. The default is 0 (no limit).
+ */
+@property (assign, nonatomic) NSInteger titleNumberOfLines;
+
+/**
+ The maximum number of lines for the message. The default is 0 (no limit).
+ */
+@property (assign, nonatomic) NSInteger messageNumberOfLines;
+
+/**
+ Enable or disable a shadow on the toast view. Default is `NO`.
+ */
+@property (assign, nonatomic) BOOL displayShadow;
+
+/**
+ The shadow color. Default is `[UIColor blackColor]`.
+ */
+@property (strong, nonatomic) UIColor *shadowColor;
+
+/**
+ A value from 0.0 to 1.0, representing the opacity of the shadow.
+ Default is 0.8 (80% opacity).
+ */
+@property (assign, nonatomic) CGFloat shadowOpacity;
+
+/**
+ The shadow radius. Default is 6.0.
+ */
+@property (assign, nonatomic) CGFloat shadowRadius;
+
+/**
+ The shadow offset. The default is `CGSizeMake(4.0, 4.0)`.
+ */
+@property (assign, nonatomic) CGSize shadowOffset;
+
+/**
+ The image size. The default is `CGSizeMake(80.0, 80.0)`.
+ */
+@property (assign, nonatomic) CGSize imageSize;
+
+/**
+ The size of the toast activity view when `makeToastActivity:` is called.
+ Default is `CGSizeMake(100.0, 100.0)`.
+ */
+@property (assign, nonatomic) CGSize activitySize;
+
+/**
+ The fade in/out animation duration. Default is 0.2.
+ */
+@property (assign, nonatomic) NSTimeInterval fadeDuration;
+
+/**
+ Creates a new instance of `CSToastStyle` with all the default values set.
+ */
+- (instancetype)initWithDefaultStyle NS_DESIGNATED_INITIALIZER;
+
+/**
+ @warning Only the designated initializer should be used to create
+ an instance of `CSToastStyle`.
+ */
+- (instancetype)init NS_UNAVAILABLE;
+
+@end
+
+/**
+ `CSToastManager` provides general configuration options for all toast
+ notifications. Backed by a singleton instance.
+ */
+@interface CSToastManager : NSObject
+
+/**
+ Sets the shared style on the singleton. The shared style is used whenever
+ a `makeToast:` method (or `toastViewForMessage:title:image:style:`) is called
+ with with a nil style. By default, this is set to `CSToastStyle`'s default
+ style.
+ 
+ @param sharedStyle the shared style
+ */
++ (void)setSharedStyle:(CSToastStyle *)sharedStyle;
+
+/**
+ Gets the shared style from the singlton. By default, this is
+ `CSToastStyle`'s default style.
+ 
+ @return the shared style
+ */
++ (CSToastStyle *)sharedStyle;
+
+/**
+ Enables or disables tap to dismiss on toast views. Default is `YES`.
+ 
+ @param tapToDismissEnabled YES or NO
+ */
++ (void)setTapToDismissEnabled:(BOOL)tapToDismissEnabled;
+
+/**
+ Returns `YES` if tap to dismiss is enabled, otherwise `NO`.
+ Default is `YES`.
+ 
+ @return BOOL YES or NO
+ */
++ (BOOL)isTapToDismissEnabled;
+
+/**
+ Enables or disables queueing behavior for toast views. When `YES`,
+ toast views will appear one after the other. When `NO`, multiple Toast
+ views will appear at the same time (potentially overlapping depending
+ on their positions). This has no effect on the toast activity view,
+ which operates independently of normal toast views. Default is `YES`.
+ 
+ @param queueEnabled YES or NO
+ */
++ (void)setQueueEnabled:(BOOL)queueEnabled;
+
+/**
+ Returns `YES` if the queue is enabled, otherwise `NO`.
+ Default is `YES`.
+ 
+ @return BOOL
+ */
++ (BOOL)isQueueEnabled;
+
+/**
+ Sets the default duration. Used for the `makeToast:` and
+ `showToast:` methods that don't require an explicit duration.
+ Default is 3.0.
+ 
+ @param duration The toast duration
+ */
++ (void)setDefaultDuration:(NSTimeInterval)duration;
+
+/**
+ Returns the default duration. Default is 3.0.
+ 
+ @return duration The toast duration
+*/
++ (NSTimeInterval)defaultDuration;
+
+/**
+ Sets the default position. Used for the `makeToast:` and
+ `showToast:` methods that don't require an explicit position.
+ Default is `CSToastPositionBottom`.
+ 
+ @param position The default center point. Can be one of the predefined
+ CSToastPosition constants or a `CGPoint` wrapped in an `NSValue` object.
+ */
++ (void)setDefaultPosition:(id)position;
+
+/**
+ Returns the default toast position. Default is `CSToastPositionBottom`.
+ 
+ @return position The default center point. Will be one of the predefined
+ CSToastPosition constants or a `CGPoint` wrapped in an `NSValue` object.
+ */
++ (id)defaultPosition;
+
+@end

+ 557 - 0
TresEnRaya/UIView+Toast.m

@@ -0,0 +1,557 @@
+//
+//  UIView+Toast.m
+//  Toast
+//
+//  Copyright (c) 2011-2016 Charles Scalesse.
+//
+//  Permission is hereby granted, free of charge, to any person obtaining a
+//  copy of this software and associated documentation files (the
+//  "Software"), to deal in the Software without restriction, including
+//  without limitation the rights to use, copy, modify, merge, publish,
+//  distribute, sublicense, and/or sell copies of the Software, and to
+//  permit persons to whom the Software is furnished to do so, subject to
+//  the following conditions:
+//
+//  The above copyright notice and this permission notice shall be included
+//  in all copies or substantial portions of the Software.
+//
+//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+//  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+//  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+//  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+//  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+//  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+//  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+#import "UIView+Toast.h"
+#import <QuartzCore/QuartzCore.h>
+#import <objc/runtime.h>
+
+NSString * CSToastPositionTop       = @"CSToastPositionTop";
+NSString * CSToastPositionCenter    = @"CSToastPositionCenter";
+NSString * CSToastPositionBottom    = @"CSToastPositionBottom";
+
+// Keys for values associated with toast views
+static const NSString * CSToastTimerKey             = @"CSToastTimerKey";
+static const NSString * CSToastDurationKey          = @"CSToastDurationKey";
+static const NSString * CSToastPositionKey          = @"CSToastPositionKey";
+static const NSString * CSToastCompletionKey        = @"CSToastCompletionKey";
+
+// Keys for values associated with self
+static const NSString * CSToastActiveKey            = @"CSToastActiveKey";
+static const NSString * CSToastActivityViewKey      = @"CSToastActivityViewKey";
+static const NSString * CSToastQueueKey             = @"CSToastQueueKey";
+
+@interface UIView (ToastPrivate)
+
+/**
+ These private methods are being prefixed with "cs_" to reduce the likelihood of non-obvious 
+ naming conflicts with other UIView methods.
+ 
+ @discussion Should the public API also use the cs_ prefix? Technically it should, but it
+ results in code that is less legible. The current public method names seem unlikely to cause
+ conflicts so I think we should favor the cleaner API for now.
+ */
+- (void)cs_showToast:(UIView *)toast duration:(NSTimeInterval)duration position:(id)position;
+- (void)cs_hideToast:(UIView *)toast;
+- (void)cs_hideToast:(UIView *)toast fromTap:(BOOL)fromTap;
+- (void)cs_toastTimerDidFinish:(NSTimer *)timer;
+- (void)cs_handleToastTapped:(UITapGestureRecognizer *)recognizer;
+- (CGPoint)cs_centerPointForPosition:(id)position withToast:(UIView *)toast;
+- (NSMutableArray *)cs_toastQueue;
+
+@end
+
+@implementation UIView (Toast)
+
+#pragma mark - Make Toast Methods
+
+- (void)makeToast:(NSString *)message {
+    [self makeToast:message duration:[CSToastManager defaultDuration] position:[CSToastManager defaultPosition] style:nil];
+}
+
+- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position {
+    [self makeToast:message duration:duration position:position style:nil];
+}
+
+- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position style:(CSToastStyle *)style {
+    UIView *toast = [self toastViewForMessage:message title:nil image:nil style:style];
+    [self showToast:toast duration:duration position:position completion:nil];
+}
+
+- (void)makeToast:(NSString *)message duration:(NSTimeInterval)duration position:(id)position title:(NSString *)title image:(UIImage *)image style:(CSToastStyle *)style completion:(void(^)(BOOL didTap))completion {
+    UIView *toast = [self toastViewForMessage:message title:title image:image style:style];
+    [self showToast:toast duration:duration position:position completion:completion];
+}
+
+#pragma mark - Show Toast Methods
+
+- (void)showToast:(UIView *)toast {
+    [self showToast:toast duration:[CSToastManager defaultDuration] position:[CSToastManager defaultPosition] completion:nil];
+}
+
+- (void)showToast:(UIView *)toast duration:(NSTimeInterval)duration position:(id)position completion:(void(^)(BOOL didTap))completion {
+    // sanity
+    if (toast == nil) return;
+    
+    // store the completion block on the toast view
+    objc_setAssociatedObject(toast, &CSToastCompletionKey, completion, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+    
+    if ([CSToastManager isQueueEnabled] && [self.cs_activeToasts count] > 0) {
+        // we're about to queue this toast view so we need to store the duration and position as well
+        objc_setAssociatedObject(toast, &CSToastDurationKey, @(duration), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+        objc_setAssociatedObject(toast, &CSToastPositionKey, position, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+        
+        // enqueue
+        [self.cs_toastQueue addObject:toast];
+    } else {
+        // present
+        [self cs_showToast:toast duration:duration position:position];
+    }
+}
+
+#pragma mark - Hide Toast Method
+
+- (void)hideToasts {
+    for (UIView *toast in [self cs_activeToasts]) {
+        [self hideToast:toast];
+    }
+}
+
+- (void)hideToast:(UIView *)toast {
+    // sanity
+    if (!toast || ![[self cs_activeToasts] containsObject:toast]) return;
+    
+    NSTimer *timer = (NSTimer *)objc_getAssociatedObject(toast, &CSToastTimerKey);
+    [timer invalidate];
+    
+    [self cs_hideToast:toast];
+}
+
+#pragma mark - Private Show/Hide Methods
+
+- (void)cs_showToast:(UIView *)toast duration:(NSTimeInterval)duration position:(id)position {
+    toast.center = [self cs_centerPointForPosition:position withToast:toast];
+    toast.alpha = 0.0;
+    
+    if ([CSToastManager isTapToDismissEnabled]) {
+        UITapGestureRecognizer *recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(cs_handleToastTapped:)];
+        [toast addGestureRecognizer:recognizer];
+        toast.userInteractionEnabled = YES;
+        toast.exclusiveTouch = YES;
+    }
+    
+    [[self cs_activeToasts] addObject:toast];
+    
+    [self addSubview:toast];
+    
+    [UIView animateWithDuration:[[CSToastManager sharedStyle] fadeDuration]
+                          delay:0.0
+                        options:(UIViewAnimationOptionCurveEaseOut | UIViewAnimationOptionAllowUserInteraction)
+                     animations:^{
+                         toast.alpha = 1.0;
+                     } completion:^(BOOL finished) {
+                         NSTimer *timer = [NSTimer timerWithTimeInterval:duration target:self selector:@selector(cs_toastTimerDidFinish:) userInfo:toast repeats:NO];
+                         [[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
+                         objc_setAssociatedObject(toast, &CSToastTimerKey, timer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+                     }];
+}
+
+- (void)cs_hideToast:(UIView *)toast {
+    [self cs_hideToast:toast fromTap:NO];
+}
+    
+- (void)cs_hideToast:(UIView *)toast fromTap:(BOOL)fromTap {
+    [UIView animateWithDuration:[[CSToastManager sharedStyle] fadeDuration]
+                          delay:0.0
+                        options:(UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionBeginFromCurrentState)
+                     animations:^{
+                         toast.alpha = 0.0;
+                     } completion:^(BOOL finished) {
+                         [toast removeFromSuperview];
+                         
+                         // remove
+                         [[self cs_activeToasts] removeObject:toast];
+                         
+                         // execute the completion block, if necessary
+                         void (^completion)(BOOL didTap) = objc_getAssociatedObject(toast, &CSToastCompletionKey);
+                         if (completion) {
+                             completion(fromTap);
+                         }
+                         
+                         if ([self.cs_toastQueue count] > 0) {
+                             // dequeue
+                             UIView *nextToast = [[self cs_toastQueue] firstObject];
+                             [[self cs_toastQueue] removeObjectAtIndex:0];
+                             
+                             // present the next toast
+                             NSTimeInterval duration = [objc_getAssociatedObject(nextToast, &CSToastDurationKey) doubleValue];
+                             id position = objc_getAssociatedObject(nextToast, &CSToastPositionKey);
+                             [self cs_showToast:nextToast duration:duration position:position];
+                         }
+                     }];
+}
+
+#pragma mark - View Construction
+
+- (UIView *)toastViewForMessage:(NSString *)message title:(NSString *)title image:(UIImage *)image style:(CSToastStyle *)style {
+    // sanity
+    if(message == nil && title == nil && image == nil) return nil;
+    
+    // default to the shared style
+    if (style == nil) {
+        style = [CSToastManager sharedStyle];
+    }
+    
+    // dynamically build a toast view with any combination of message, title, & image
+    UILabel *messageLabel = nil;
+    UILabel *titleLabel = nil;
+    UIImageView *imageView = nil;
+    
+    UIView *wrapperView = [[UIView alloc] init];
+    wrapperView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin);
+    wrapperView.layer.cornerRadius = style.cornerRadius;
+    
+    if (style.displayShadow) {
+        wrapperView.layer.shadowColor = style.shadowColor.CGColor;
+        wrapperView.layer.shadowOpacity = style.shadowOpacity;
+        wrapperView.layer.shadowRadius = style.shadowRadius;
+        wrapperView.layer.shadowOffset = style.shadowOffset;
+    }
+    
+    wrapperView.backgroundColor = style.backgroundColor;
+    
+    if(image != nil) {
+        imageView = [[UIImageView alloc] initWithImage:image];
+        imageView.contentMode = UIViewContentModeScaleAspectFit;
+        imageView.frame = CGRectMake(style.horizontalPadding, style.verticalPadding, style.imageSize.width, style.imageSize.height);
+    }
+    
+    CGRect imageRect = CGRectZero;
+    
+    if(imageView != nil) {
+        imageRect.origin.x = style.horizontalPadding;
+        imageRect.origin.y = style.verticalPadding;
+        imageRect.size.width = imageView.bounds.size.width;
+        imageRect.size.height = imageView.bounds.size.height;
+    }
+    
+    if (title != nil) {
+        titleLabel = [[UILabel alloc] init];
+        titleLabel.numberOfLines = style.titleNumberOfLines;
+        titleLabel.font = style.titleFont;
+        titleLabel.textAlignment = style.titleAlignment;
+        titleLabel.lineBreakMode = NSLineBreakByTruncatingTail;
+        titleLabel.textColor = style.titleColor;
+        titleLabel.backgroundColor = [UIColor clearColor];
+        titleLabel.alpha = 1.0;
+        titleLabel.text = title;
+        
+        // size the title label according to the length of the text
+        CGSize maxSizeTitle = CGSizeMake((self.bounds.size.width * style.maxWidthPercentage) - imageRect.size.width, self.bounds.size.height * style.maxHeightPercentage);
+        CGSize expectedSizeTitle = [titleLabel sizeThatFits:maxSizeTitle];
+        // UILabel can return a size larger than the max size when the number of lines is 1
+        expectedSizeTitle = CGSizeMake(MIN(maxSizeTitle.width, expectedSizeTitle.width), MIN(maxSizeTitle.height, expectedSizeTitle.height));
+        titleLabel.frame = CGRectMake(0.0, 0.0, expectedSizeTitle.width, expectedSizeTitle.height);
+    }
+    
+    if (message != nil) {
+        messageLabel = [[UILabel alloc] init];
+        messageLabel.numberOfLines = style.messageNumberOfLines;
+        messageLabel.font = style.messageFont;
+        messageLabel.textAlignment = style.messageAlignment;
+        messageLabel.lineBreakMode = NSLineBreakByTruncatingTail;
+        messageLabel.textColor = style.messageColor;
+        messageLabel.backgroundColor = [UIColor clearColor];
+        messageLabel.alpha = 1.0;
+        messageLabel.text = message;
+        
+        CGSize maxSizeMessage = CGSizeMake((self.bounds.size.width * style.maxWidthPercentage) - imageRect.size.width, self.bounds.size.height * style.maxHeightPercentage);
+        CGSize expectedSizeMessage = [messageLabel sizeThatFits:maxSizeMessage];
+        // UILabel can return a size larger than the max size when the number of lines is 1
+        expectedSizeMessage = CGSizeMake(MIN(maxSizeMessage.width, expectedSizeMessage.width), MIN(maxSizeMessage.height, expectedSizeMessage.height));
+        messageLabel.frame = CGRectMake(0.0, 0.0, expectedSizeMessage.width, expectedSizeMessage.height);
+    }
+    
+    CGRect titleRect = CGRectZero;
+    
+    if(titleLabel != nil) {
+        titleRect.origin.x = imageRect.origin.x + imageRect.size.width + style.horizontalPadding;
+        titleRect.origin.y = style.verticalPadding;
+        titleRect.size.width = titleLabel.bounds.size.width;
+        titleRect.size.height = titleLabel.bounds.size.height;
+    }
+    
+    CGRect messageRect = CGRectZero;
+    
+    if(messageLabel != nil) {
+        messageRect.origin.x = imageRect.origin.x + imageRect.size.width + style.horizontalPadding;
+        messageRect.origin.y = titleRect.origin.y + titleRect.size.height + style.verticalPadding;
+        messageRect.size.width = messageLabel.bounds.size.width;
+        messageRect.size.height = messageLabel.bounds.size.height;
+    }
+    
+    CGFloat longerWidth = MAX(titleRect.size.width, messageRect.size.width);
+    CGFloat longerX = MAX(titleRect.origin.x, messageRect.origin.x);
+    
+    // Wrapper width uses the longerWidth or the image width, whatever is larger. Same logic applies to the wrapper height.
+    CGFloat wrapperWidth = MAX((imageRect.size.width + (style.horizontalPadding * 2.0)), (longerX + longerWidth + style.horizontalPadding));
+    CGFloat wrapperHeight = MAX((messageRect.origin.y + messageRect.size.height + style.verticalPadding), (imageRect.size.height + (style.verticalPadding * 2.0)));
+    
+    wrapperView.frame = CGRectMake(0.0, 0.0, wrapperWidth, wrapperHeight);
+    
+    if(titleLabel != nil) {
+        titleLabel.frame = titleRect;
+        [wrapperView addSubview:titleLabel];
+    }
+    
+    if(messageLabel != nil) {
+        messageLabel.frame = messageRect;
+        [wrapperView addSubview:messageLabel];
+    }
+    
+    if(imageView != nil) {
+        [wrapperView addSubview:imageView];
+    }
+    
+    return wrapperView;
+}
+
+#pragma mark - Storage
+
+- (NSMutableArray *)cs_activeToasts {
+    NSMutableArray *cs_activeToasts = objc_getAssociatedObject(self, &CSToastActiveKey);
+    if (cs_activeToasts == nil) {
+        cs_activeToasts = [[NSMutableArray alloc] init];
+        objc_setAssociatedObject(self, &CSToastActiveKey, cs_activeToasts, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+    }
+    return cs_activeToasts;
+}
+
+- (NSMutableArray *)cs_toastQueue {
+    NSMutableArray *cs_toastQueue = objc_getAssociatedObject(self, &CSToastQueueKey);
+    if (cs_toastQueue == nil) {
+        cs_toastQueue = [[NSMutableArray alloc] init];
+        objc_setAssociatedObject(self, &CSToastQueueKey, cs_toastQueue, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+    }
+    return cs_toastQueue;
+}
+
+#pragma mark - Events
+
+- (void)cs_toastTimerDidFinish:(NSTimer *)timer {
+    [self cs_hideToast:(UIView *)timer.userInfo];
+}
+
+- (void)cs_handleToastTapped:(UITapGestureRecognizer *)recognizer {
+    UIView *toast = recognizer.view;
+    NSTimer *timer = (NSTimer *)objc_getAssociatedObject(toast, &CSToastTimerKey);
+    [timer invalidate];
+    
+    [self cs_hideToast:toast fromTap:YES];
+}
+
+#pragma mark - Activity Methods
+
+- (void)makeToastActivity:(id)position {
+    // sanity
+    UIView *existingActivityView = (UIView *)objc_getAssociatedObject(self, &CSToastActivityViewKey);
+    if (existingActivityView != nil) return;
+    
+    CSToastStyle *style = [CSToastManager sharedStyle];
+    
+    UIView *activityView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, style.activitySize.width, style.activitySize.height)];
+    activityView.center = [self cs_centerPointForPosition:position withToast:activityView];
+    activityView.backgroundColor = style.backgroundColor;
+    activityView.alpha = 0.0;
+    activityView.autoresizingMask = (UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin);
+    activityView.layer.cornerRadius = style.cornerRadius;
+    
+    if (style.displayShadow) {
+        activityView.layer.shadowColor = style.shadowColor.CGColor;
+        activityView.layer.shadowOpacity = style.shadowOpacity;
+        activityView.layer.shadowRadius = style.shadowRadius;
+        activityView.layer.shadowOffset = style.shadowOffset;
+    }
+    
+    UIActivityIndicatorView *activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
+    activityIndicatorView.center = CGPointMake(activityView.bounds.size.width / 2, activityView.bounds.size.height / 2);
+    [activityView addSubview:activityIndicatorView];
+    [activityIndicatorView startAnimating];
+    
+    // associate the activity view with self
+    objc_setAssociatedObject (self, &CSToastActivityViewKey, activityView, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+    
+    [self addSubview:activityView];
+    
+    [UIView animateWithDuration:style.fadeDuration
+                          delay:0.0
+                        options:UIViewAnimationOptionCurveEaseOut
+                     animations:^{
+                         activityView.alpha = 1.0;
+                     } completion:nil];
+}
+
+- (void)hideToastActivity {
+    UIView *existingActivityView = (UIView *)objc_getAssociatedObject(self, &CSToastActivityViewKey);
+    if (existingActivityView != nil) {
+        [UIView animateWithDuration:[[CSToastManager sharedStyle] fadeDuration]
+                              delay:0.0
+                            options:(UIViewAnimationOptionCurveEaseIn | UIViewAnimationOptionBeginFromCurrentState)
+                         animations:^{
+                             existingActivityView.alpha = 0.0;
+                         } completion:^(BOOL finished) {
+                             [existingActivityView removeFromSuperview];
+                             objc_setAssociatedObject (self, &CSToastActivityViewKey, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+                         }];
+    }
+}
+
+#pragma mark - Helpers
+
+- (CGPoint)cs_centerPointForPosition:(id)point withToast:(UIView *)toast {
+    CSToastStyle *style = [CSToastManager sharedStyle];
+    
+    if([point isKindOfClass:[NSString class]]) {
+        if([point caseInsensitiveCompare:CSToastPositionTop] == NSOrderedSame) {
+            return CGPointMake(self.bounds.size.width/2, (toast.frame.size.height / 2) + style.verticalPadding);
+        } else if([point caseInsensitiveCompare:CSToastPositionCenter] == NSOrderedSame) {
+            return CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
+        }
+    } else if ([point isKindOfClass:[NSValue class]]) {
+        return [point CGPointValue];
+    }
+    
+    // default to bottom
+    return CGPointMake(self.bounds.size.width/2, (self.bounds.size.height - (toast.frame.size.height / 2)) - style.verticalPadding);
+}
+
+@end
+
+@implementation CSToastStyle
+
+#pragma mark - Constructors
+
+- (instancetype)initWithDefaultStyle {
+    self = [super init];
+    if (self) {
+        self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.8];
+        self.titleColor = [UIColor whiteColor];
+        self.messageColor = [UIColor whiteColor];
+        self.maxWidthPercentage = 0.8;
+        self.maxHeightPercentage = 0.8;
+        self.horizontalPadding = 10.0;
+        self.verticalPadding = 10.0;
+        self.cornerRadius = 10.0;
+        self.titleFont = [UIFont boldSystemFontOfSize:16.0];
+        self.messageFont = [UIFont systemFontOfSize:16.0];
+        self.titleAlignment = NSTextAlignmentLeft;
+        self.messageAlignment = NSTextAlignmentLeft;
+        self.titleNumberOfLines = 0;
+        self.messageNumberOfLines = 0;
+        self.displayShadow = NO;
+        self.shadowOpacity = 0.8;
+        self.shadowRadius = 6.0;
+        self.shadowOffset = CGSizeMake(4.0, 4.0);
+        self.imageSize = CGSizeMake(80.0, 80.0);
+        self.activitySize = CGSizeMake(100.0, 100.0);
+        self.fadeDuration = 0.2;
+    }
+    return self;
+}
+
+- (void)setMaxWidthPercentage:(CGFloat)maxWidthPercentage {
+    _maxWidthPercentage = MAX(MIN(maxWidthPercentage, 1.0), 0.0);
+}
+
+- (void)setMaxHeightPercentage:(CGFloat)maxHeightPercentage {
+    _maxHeightPercentage = MAX(MIN(maxHeightPercentage, 1.0), 0.0);
+}
+
+- (instancetype)init NS_UNAVAILABLE {
+    return nil;
+}
+
+@end
+
+@interface CSToastManager ()
+
+@property (strong, nonatomic) CSToastStyle *sharedStyle;
+@property (assign, nonatomic, getter=isTapToDismissEnabled) BOOL tapToDismissEnabled;
+@property (assign, nonatomic, getter=isQueueEnabled) BOOL queueEnabled;
+@property (assign, nonatomic) NSTimeInterval defaultDuration;
+@property (strong, nonatomic) id defaultPosition;
+
+@end
+
+@implementation CSToastManager
+
+#pragma mark - Constructors
+
++ (instancetype)sharedManager {
+    static CSToastManager *_sharedManager = nil;
+    static dispatch_once_t oncePredicate;
+    dispatch_once(&oncePredicate, ^{
+        _sharedManager = [[self alloc] init];
+    });
+    
+    return _sharedManager;
+}
+
+- (instancetype)init {
+    self = [super init];
+    if (self) {
+        self.sharedStyle = [[CSToastStyle alloc] initWithDefaultStyle];
+        self.tapToDismissEnabled = YES;
+        self.queueEnabled = YES;
+        self.defaultDuration = 3.0;
+        self.defaultPosition = CSToastPositionBottom;
+    }
+    return self;
+}
+
+#pragma mark - Singleton Methods
+
++ (void)setSharedStyle:(CSToastStyle *)sharedStyle {
+    [[self sharedManager] setSharedStyle:sharedStyle];
+}
+
++ (CSToastStyle *)sharedStyle {
+    return [[self sharedManager] sharedStyle];
+}
+
++ (void)setTapToDismissEnabled:(BOOL)tapToDismissEnabled {
+    [[self sharedManager] setTapToDismissEnabled:tapToDismissEnabled];
+}
+
++ (BOOL)isTapToDismissEnabled {
+    return [[self sharedManager] isTapToDismissEnabled];
+}
+
++ (void)setQueueEnabled:(BOOL)queueEnabled {
+    [[self sharedManager] setQueueEnabled:queueEnabled];
+}
+
++ (BOOL)isQueueEnabled {
+    return [[self sharedManager] isQueueEnabled];
+}
+
++ (void)setDefaultDuration:(NSTimeInterval)duration {
+    [[self sharedManager] setDefaultDuration:duration];
+}
+
++ (NSTimeInterval)defaultDuration {
+    return [[self sharedManager] defaultDuration];
+}
+
++ (void)setDefaultPosition:(id)position {
+    if ([position isKindOfClass:[NSString class]] || [position isKindOfClass:[NSValue class]]) {
+        [[self sharedManager] setDefaultPosition:position];
+    }
+}
+
++ (id)defaultPosition {
+    return [[self sharedManager] defaultPosition];
+}
+
+@end

+ 67 - 63
TresEnRaya/ViewController.m

@@ -1,30 +1,31 @@
 #import "ViewController.h"
-#import "SoundManager.h";
-
-@interface ViewController ()
-
-@end
-
-@implementation ViewController
+#import "SoundManager.h"
+#import "UIView+Toast.h"
 
+@interface ViewController (){
 NSMutableArray *arrayDeBotones;
 UIButton *nuevoBoton;
 UIView *menu;
 float anchoVentana;
 float altoVentana;
-int jugador=1;
-int jugada=0;
+int jugador;
+int jugada;
+}@end
+
+@implementation ViewController
 
 - (void)viewDidLoad {
     [super viewDidLoad];
     anchoVentana=self.view.bounds.size.width;
     altoVentana=self.view.bounds.size.height;
-	[self agregarBotones];
-	[[SoundManager sharedManager] setMusicVolume:0.2];
-			[[SoundManager sharedManager] playMusic:@"intro.mp3" looping:YES];
-			    }
+jugador=1;
+jugada=0;
+[self agregarBotones];
+[[SoundManager sharedManager] setMusicVolume:0.2];
+[[SoundManager sharedManager] playMusic:@"intro.mp3" looping:YES];
+    }
 
-	- (void) agregarBotones{
+- (void) agregarBotones{
 float anchoBoton=anchoVentana/3;
 float altoBoton=altoVentana/3;
         arrayDeBotones = [[NSMutableArray alloc] init];
@@ -35,51 +36,51 @@ for (int i=0; i<9; i++) {
 [nuevoBoton setBackgroundColor:[UIColor blueColor]];
     [nuevoBoton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
     [nuevoBoton setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
-	    [nuevoBoton setAccessibilityLabel:@"Casilla vacía"];
+    [nuevoBoton setAccessibilityLabel:@"Casilla vacía"];
     [nuevoBoton addTarget:self action:@selector(botonPulsado:) forControlEvents:UIControlEventTouchUpInside];
-	nuevoBoton.tag = i;
+nuevoBoton.tag = i;
 nuevoBoton.titleLabel.font = [UIFont boldSystemFontOfSize:15];
     nuevoBoton.layer.masksToBounds = YES;
-	nuevoBoton.layer.cornerRadius = 5;
+nuevoBoton.layer.cornerRadius = 5;
     nuevoBoton.layer.borderWidth = 1;
     nuevoBoton.layer.borderColor = [[UIColor blackColor] CGColor];
-                 				 [arrayDeBotones addObject:nuevoBoton];
-				 if(x==2){
-				 x=0;
-				 y=y+1;
-				 }else{
-				 x=x+1;
-				 }
-				 }
-				 for(UIButton *boton in arrayDeBotones){
+                  [arrayDeBotones addObject:nuevoBoton];
+ if(x==2){
+ x=0;
+ y=y+1;
+ }else{
+ x=x+1;
+ }
+ }
+ for(UIButton *boton in arrayDeBotones){
     [self.view addSubview:boton];
 }
-				 }
+ }
 
-				 -(void) botonPulsado:(UIButton *) sender {
-				 if((jugador>0)&&([self tituloBoton:sender.tag]==nil)){
+ -(void) botonPulsado:(UIButton *) sender {
+ if((jugador>0)&&([self tituloBoton:sender.tag]==nil)){
     switch(jugador){
         case 1:
             [sender setAccessibilityLabel:@"X"];
             [sender setTitle:@"X" forState:UIControlStateNormal];
-			[[SoundManager sharedManager] playSound:@"gato.mp3" looping:NO];
-			            						            break;
+[[SoundManager sharedManager] playSound:@"gato.mp3" looping:NO];
+                        break;
         case 2:
             [sender setAccessibilityLabel:@"O"];
             [sender setTitle:@"O" forState:UIControlStateNormal];
-			[[SoundManager sharedManager] playSound:@"perro.mp3" looping:NO];
-			                        						            break;
+[[SoundManager sharedManager] playSound:@"perro.mp3" looping:NO];
+                                    break;
     }
                      jugada=jugada+1;
                      int resultado=[self ComprobarPartida];
-	if(resultado>0) {
+if(resultado>0) {
         [self finPartida:resultado];
-	}else{
-	[self turnoSiguiente];
-	}
-	}else{
-	[[SoundManager sharedManager] playSound:@"vaca.mp3" looping:NO];
-	}
+}else{
+[self turnoSiguiente];
+}
+}else{
+[[SoundManager sharedManager] playSound:@"vaca.mp3" looping:NO];
+}
 }
 
 -(void) turnoSiguiente{
@@ -91,27 +92,30 @@ case 2:
 jugador=1;
         break;
         }
+[self.view makeToast:[NSString stringWithFormat:@"Turno del jugador %i", jugador] 
+            duration:3.0
+            position:CSToastPositionCenter];
 }
 
 - (int) ComprobarPartida{
     if (([[self tituloBoton:0] isEqual:[self tituloBoton:1]])&&([[self tituloBoton:1] isEqual:[self tituloBoton:2]])) return 1;
-	if (([[self tituloBoton:3] isEqual:[self tituloBoton:4]])&&([[self tituloBoton:4] isEqual:[self tituloBoton:5]])) return 1;
-	if (([[self tituloBoton:6] isEqual:[self tituloBoton:7]])&&([[self tituloBoton:7] isEqual:[self tituloBoton:8]])) return 1;
-	if (([[self tituloBoton:0] isEqual:[self tituloBoton:3]])&&([[self tituloBoton:3] isEqual:[self tituloBoton:6]])) return 1;
-	if (([[self tituloBoton:1] isEqual:[self tituloBoton:4]])&&([[self tituloBoton:4] isEqual:[self tituloBoton:7]])) return 1;
-	if (([[self tituloBoton:2] isEqual:[self tituloBoton:5]])&&([[self tituloBoton:5] isEqual:[self tituloBoton:8]])) return 1;
-	if (([[self tituloBoton:0] isEqual:[self tituloBoton:4]])&&([[self tituloBoton:4] isEqual:[self tituloBoton:8]])) return 1;
-	if (([[self tituloBoton:2] isEqual:[self tituloBoton:4]])&&([[self tituloBoton:4] isEqual:[self tituloBoton:6]])) return 1;
+if (([[self tituloBoton:3] isEqual:[self tituloBoton:4]])&&([[self tituloBoton:4] isEqual:[self tituloBoton:5]])) return 1;
+if (([[self tituloBoton:6] isEqual:[self tituloBoton:7]])&&([[self tituloBoton:7] isEqual:[self tituloBoton:8]])) return 1;
+if (([[self tituloBoton:0] isEqual:[self tituloBoton:3]])&&([[self tituloBoton:3] isEqual:[self tituloBoton:6]])) return 1;
+if (([[self tituloBoton:1] isEqual:[self tituloBoton:4]])&&([[self tituloBoton:4] isEqual:[self tituloBoton:7]])) return 1;
+if (([[self tituloBoton:2] isEqual:[self tituloBoton:5]])&&([[self tituloBoton:5] isEqual:[self tituloBoton:8]])) return 1;
+if (([[self tituloBoton:0] isEqual:[self tituloBoton:4]])&&([[self tituloBoton:4] isEqual:[self tituloBoton:8]])) return 1;
+if (([[self tituloBoton:2] isEqual:[self tituloBoton:4]])&&([[self tituloBoton:4] isEqual:[self tituloBoton:6]])) return 1;
     if(jugada==9) return 2;
-	return 0;
-	}
+return 0;
+}
 
-	-(NSString*) tituloBoton:(int) tagBoton{
+-(NSString*) tituloBoton:(int) tagBoton{
 for(UIButton *boton in arrayDeBotones){
     if(boton.tag==tagBoton) return boton.currentTitle;
 }
-				 return NULL;
-				 }
+ return NULL;
+ }
 
 -(void) finPartida:(int) resultado{
     NSString *mensajeAlerta;
@@ -125,10 +129,10 @@ mensajeAlerta=@"La partida ha finalizado con un empate";
 [[SoundManager sharedManager] playSound:@"abucheo.mp3" looping:NO];
 break;
 }
-	UIAlertController *alerta = [UIAlertController 
-	alertControllerWithTitle:@"¡Partida terminada!" 
-	message:mensajeAlerta
-	preferredStyle:UIAlertControllerStyleAlert];
+UIAlertController *alerta = [UIAlertController 
+alertControllerWithTitle:@"¡Partida terminada!" 
+message:mensajeAlerta
+preferredStyle:UIAlertControllerStyleAlert];
 UIAlertAction *ok=[UIAlertAction 
 actionWithTitle:@"Aceptar" 
 style:UIAlertActionStyleDefault 
@@ -152,8 +156,8 @@ for(UIButton *boton in arrayDeBotones){
 [arrayDeBotones removeAllObjects];
 menu = [[UIView alloc]
         initWithFrame:CGRectMake(20,20,anchoVentana-40,altoVentana-40)];
-    	float anchoVistaMenu=menu.bounds.size.width;
-	float altoVistaMenu=menu.bounds.size.height;
+    float anchoVistaMenu=menu.bounds.size.width;
+float altoVistaMenu=menu.bounds.size.height;
 UILabel *MenuEtiqueta = [[UILabel alloc]
 initWithFrame:CGRectMake(0,0,anchoVistaMenu,altoVistaMenu/4*3)];
 MenuEtiqueta.text=[NSString stringWithFormat:@"Partida terminada. %@", mensaje];
@@ -163,16 +167,16 @@ initWithFrame:CGRectMake(0,altoVistaMenu/4*3+1,anchoVistaMenu,altoVistaMenu/4)];
 [menuBoton setBackgroundColor:[UIColor blueColor]];
     [menuBoton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
     [menuBoton setTitleColor:[UIColor redColor] forState:UIControlStateHighlighted];
-	[menuBoton setTitle:@"Jugar de nuevo" forState:UIControlStateNormal];
+[menuBoton setTitle:@"Jugar de nuevo" forState:UIControlStateNormal];
         [menuBoton addTarget:self action:@selector(jugarDeNuevo:) forControlEvents:UIControlEventTouchUpInside];
-	menuBoton.tag = 9;
+menuBoton.tag = 9;
 menuBoton.titleLabel.font = [UIFont boldSystemFontOfSize:15];
     menuBoton.layer.masksToBounds = YES;
-	menuBoton.layer.cornerRadius = 5;
+menuBoton.layer.cornerRadius = 5;
     menuBoton.layer.borderWidth = 1;
     menuBoton.layer.borderColor = [[UIColor blackColor] CGColor];
 [menu addSubview:menuBoton];
-		[self.view addSubview:menu];
+[self.view addSubview:menu];
 }
 
 -(void) jugarDeNuevo:(UIButton *) sender {
@@ -186,4 +190,4 @@ jugador=1;
     [super didReceiveMemoryWarning];
   }
 
-				 @end
+ @end