Created
June 18, 2017 19:41
Star
You must be signed in to star a gist
Buzztouch 4.0 fix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright 2012, Andy Kitts | |
* | |
* All rights reserved. | |
* | |
* Redistribution and use in source and binary forms, with or without modification, are | |
* permitted provided that the following conditions are met: | |
* | |
* Redistributions of source code must retain the above copyright notice which includes the | |
* name(s) of the copyright holders. It must also retain this list of conditions and the | |
* following disclaimer. | |
* | |
* Redistributions in binary form must reproduce the above copyright notice, this list | |
* of conditions and the following disclaimer in the documentation and/or other materials | |
* provided with the distribution. | |
* | |
* Neither the name of David Book, or buzztouch.com nor the names of its contributors | |
* may be used to endorse or promote products derived from this software without specific | |
* prior written permission. | |
* | |
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | |
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, | |
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY | |
* OF SUCH DAMAGE. | |
*/ | |
#import <UIKit/UIKit.h> | |
#import <Foundation/Foundation.h> | |
#import "BT_application.h" | |
#import "BT_strings.h" | |
#import "BT_viewUtilities.h" | |
#import "BT_appDelegate.h" | |
#import "BT_item.h" | |
#import "BT_debugger.h" | |
#import "Buzz_carousel.h" | |
#import "BT_item.h" | |
#import "BT_downloader.h" | |
#import "BT_fileManager.h" | |
#import "ReflectionView.h" | |
#import "iCarousel.h" | |
@interface Buzz_carousel () | |
@property (nonatomic, retain) NSMutableArray *items; | |
@property (nonatomic, assign) NSTimer *scrollTimer; | |
@property (nonatomic, assign) NSTimeInterval lastTime; | |
@end | |
@implementation Buzz_carousel | |
@synthesize aCarousel, label, wrap, AKAlbums, descriptions, menuItems; | |
@synthesize saveAsFileName, downloader, isLoading, didInit; | |
@synthesize scrollTimer; | |
@synthesize lastTime; | |
//viewDidLoad... | |
-(void)viewDidLoad{ | |
[BT_debugger showIt:self theMessage:@"viewDidLoad"]; | |
[super viewDidLoad]; | |
//set the carousel effect... | |
NSString *effect = [BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:@"iCarouselEffect" defaultValue:@"iCarouselTypeCylinder"]; | |
if([effect isEqualToString:@"iCarouselTypeCoverFlow"]) [aCarousel setType:iCarouselTypeCoverFlow]; | |
if([effect isEqualToString:@"iCarouselTypeCoverFlow2"]) [aCarousel setType:iCarouselTypeCoverFlow2]; | |
if([effect isEqualToString:@"iCarouselTypeWheel"]) [aCarousel setType:iCarouselTypeWheel]; | |
if([effect isEqualToString:@"iCarouselTypeInvertedWheel"]) [aCarousel setType:iCarouselTypeInvertedWheel]; | |
if([effect isEqualToString:@"iCarouselTypeTimeMachine"]) [aCarousel setType:iCarouselTypeTimeMachine]; | |
if([effect isEqualToString:@"iCarouselTypeInvertedTimeMachine"]) [aCarousel setType:iCarouselTypeInvertedTimeMachine]; | |
if([effect isEqualToString:@"iCarouselTypeCylinder"]) [aCarousel setType:iCarouselTypeCylinder]; | |
if([effect isEqualToString:@"iCarouselTypeInvertedCylinder"]) [aCarousel setType:iCarouselTypeInvertedCylinder]; | |
if([effect isEqualToString:@"iCarouselTypeRotary"]) [aCarousel setType:iCarouselTypeRotary]; | |
if([effect isEqualToString:@"iCarouselTypeInvertedRotary"]) [aCarousel setType:iCarouselTypeInvertedRotary]; | |
if([effect isEqualToString:@"iCarouselTypeLinear"]) [aCarousel setType:iCarouselTypeLinear]; | |
if([effect isEqualToString:@"iCarouselTypeCustom"]) [aCarousel setType:iCarouselTypeCustom]; | |
// set wether carousel is horisontal or vertical | |
aCarousel.vertical = [[BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:@"AKOrientation" defaultValue:@"0"]boolValue]; | |
if (wrap == 0){ | |
[self stopScrolling]; | |
} else { | |
[self startScrolling]; | |
} | |
} | |
//viewWillAppear... | |
-(void)viewWillAppear:(BOOL)animated{ | |
[super viewWillAppear:animated]; | |
[BT_debugger showIt:self theMessage:@"viewWillAppear"]; | |
//if we have not yet inited data.. | |
if(self.didInit == 0){ | |
[self performSelector:(@selector(loadData)) withObject:nil afterDelay:0.1]; | |
[self setDidInit:1]; | |
} | |
//show or hide the label | |
label.hidden = [[BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:@"AKShowLabel" defaultValue:@"0"]boolValue]; | |
//will caurosel data infinetely scroll | |
wrap = [[BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:@"AKWrap" defaultValue:@"0"]boolValue]; | |
if (wrap == 0){ | |
[self stopScrolling]; | |
} else { | |
[self startScrolling]; | |
} | |
// 3D effects does not work with time machine or vertical orientation | |
if (aCarousel.vertical == 1 | aCarousel.type == iCarouselTypeTimeMachine | aCarousel.type == iCarouselTypeInvertedTimeMachine) | |
{ | |
CGSize offset1 = CGSizeMake(0.0f,0.0f); | |
aCarousel.viewpointOffset = offset1; | |
CGSize offset2 = CGSizeMake(0.0f, 0.0f); | |
aCarousel.contentOffset = offset2; | |
}else{ | |
CGSize offset1 = CGSizeMake(0.0f,[[BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:@"AKViewPoint" defaultValue:@"0"]floatValue]); | |
aCarousel.viewpointOffset = offset1; | |
CGSize offset2 = CGSizeMake(0.0f, [[BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:@"AKOffset" defaultValue:@"0"]floatValue]); | |
aCarousel.contentOffset = offset2; | |
} | |
} | |
//initWithNibName... | |
-(id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil{ | |
[BT_debugger showIt:self theMessage:@"initWithNibName"]; | |
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; | |
if (self) { | |
//init arrays... | |
self.AKAlbums = [[NSMutableArray alloc] init]; | |
self.descriptions = [[NSMutableArray alloc] init]; | |
//add two emtpy images so carousel can load before data is parsed... | |
[self.AKAlbums addObject:@"blank.png"]; | |
[self.AKAlbums addObject:@"blank.png"]; | |
//add two emtpy descriptions so carousel can load before data is parsed... | |
[self.descriptions addObject:@"one"]; | |
[self.descriptions addObject:@"two"]; | |
} | |
//all done... | |
return self; | |
} | |
//load data | |
-(void)loadData{ | |
[BT_debugger showIt:self theMessage:@"loadData"]; | |
self.isLoading = TRUE; | |
//prevent interaction during operation | |
//[myTableView setScrollEnabled:FALSE]; | |
//[myTableView setAllowsSelection:FALSE]; | |
/* | |
Screen Data scenarios | |
-------------------------------- | |
a) No dataURL is provided in the screen data - use the info configured in the app's configuration file | |
b) A dataURL is provided, download now if we don't have a cache, else, download on refresh. | |
*/ | |
self.saveAsFileName = [NSString stringWithFormat:@"screenData_%@.txt", [self.screenData itemId]]; | |
//do we have a URL? | |
BOOL haveURL = FALSE; | |
if([[BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:@"dataURL" defaultValue:@""] length] > 10){ | |
haveURL = TRUE; | |
} | |
//start by filling the list from the configuration file, use these if we can't get anything from a URL | |
if([[self.screenData jsonVars] objectForKey:@"childItems"]){ | |
//init the items array... | |
self.menuItems = [[NSMutableArray alloc] init]; | |
//init arrays for albums and descriptions... | |
self.AKAlbums = [[NSMutableArray alloc] init]; | |
self.descriptions = [[NSMutableArray alloc] init]; | |
//build a list of BT_items, each one represents a carousel item in the control panel... | |
NSArray *tmpMenuItems = [[self.screenData jsonVars] objectForKey:@"childItems"]; | |
for(NSMutableDictionary *tmpMenuItem in tmpMenuItems){ | |
BT_item *thisMenuItem = [[BT_item alloc] init]; | |
thisMenuItem.itemId = [tmpMenuItem objectForKey:@"itemId"]; | |
thisMenuItem.itemType = [tmpMenuItem objectForKey:@"itemType"]; | |
thisMenuItem.jsonVars = tmpMenuItem; | |
[self.menuItems addObject:thisMenuItem]; | |
//get the image and the description for this item... | |
[self.AKAlbums addObject:[BT_strings getJsonPropertyValue:thisMenuItem.jsonVars nameOfProperty:@"itemImageFileName" defaultValue:@""]]; | |
[self.descriptions addObject:[BT_strings getJsonPropertyValue:thisMenuItem.jsonVars nameOfProperty:@"titleText" defaultValue:@""]]; | |
[thisMenuItem release]; | |
} | |
} | |
//if we have a URL, fetch.. | |
if(haveURL){ | |
//look for a previously cached version of this screens data... | |
if([BT_fileManager doesLocalFileExist:[self saveAsFileName]]){ | |
[BT_debugger showIt:self theMessage:@"parsing cached version of screen data"]; | |
NSString *staleData = [BT_fileManager readTextFileFromCacheWithEncoding:[self saveAsFileName] encodingFlag:-1]; | |
[self parseScreenData:staleData]; | |
}else{ | |
[BT_debugger showIt:self theMessage:@"no cached version of this screens data available."]; | |
[self downloadData]; | |
} | |
}else{ | |
//show the child items in the config data | |
[BT_debugger showIt:self theMessage:@"using menu items from the screens configuration data."]; | |
[self layoutScreen]; | |
} | |
} | |
//download data | |
-(void)downloadData{ | |
[BT_debugger showIt:self theMessage:[NSString stringWithFormat:@"downloading screen data from: %@", [BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:@"dataURL" defaultValue:@""]]]; | |
//flag this as the current screen | |
appDelegate.rootApp.currentScreenData = self.screenData; | |
//show progress | |
[self showProgress]; | |
NSString *tmpURL = @""; | |
if([[BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:@"dataURL" defaultValue:@""] length] > 3){ | |
//merge url variables | |
tmpURL = [BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:@"dataURL" defaultValue:@""]; | |
///merge possible variables in URL | |
NSString *useURL = [BT_strings mergeBTVariablesInString:tmpURL]; | |
NSString *escapedUrl = [useURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; | |
//fire downloader to fetch and results | |
downloader = [[BT_downloader alloc] init]; | |
[downloader setSaveAsFileName:[self saveAsFileName]]; | |
[downloader setSaveAsFileType:@"text"]; | |
[downloader setUrlString:escapedUrl]; | |
[downloader setDelegate:self]; | |
[downloader downloadFile]; | |
} | |
} | |
//parse screen data | |
-(void)parseScreenData:(NSString *)theData{ | |
[BT_debugger showIt:self theMessage:@"parseScreenData"]; | |
@try { | |
//arrays for screenData | |
self.menuItems = [[NSMutableArray alloc] init]; | |
//init arrays for albums and descriptions... | |
self.AKAlbums = [[NSMutableArray alloc] init]; | |
self.descriptions = [[NSMutableArray alloc] init]; | |
//create dictionary from the JSON string | |
NSData *jsonDataFromString = [theData dataUsingEncoding:NSUTF8StringEncoding]; | |
NSError *error; | |
id jsonData = [NSJSONSerialization JSONObjectWithData:jsonDataFromString options:0 error:&error]; | |
if(!jsonData){ | |
[self showAlert:NSLocalizedString(@"errorTitle",@"~ Error ~") theMessage:NSLocalizedString(@"appParseError", @"There was a problem parsing some configuration data. Please make sure that it is well-formed") alertTag:0]; | |
[BT_fileManager deleteFile:[self saveAsFileName]]; | |
}else{ | |
if([jsonData objectForKey:@"childItems"]){ | |
NSArray *tmpMenuItems = [jsonData objectForKey:@"childItems"]; | |
for(NSMutableDictionary *tmpMenuItem in tmpMenuItems){ | |
BT_item *thisMenuItem = [[BT_item alloc] init]; | |
thisMenuItem.itemId = [tmpMenuItem objectForKey:@"itemId"]; | |
thisMenuItem.itemType = [tmpMenuItem objectForKey:@"itemType"]; | |
thisMenuItem.jsonVars = tmpMenuItem; | |
[self.menuItems addObject:thisMenuItem]; | |
//get the image and the description for this item... | |
[self.AKAlbums addObject:[BT_strings getJsonPropertyValue:thisMenuItem.jsonVars nameOfProperty:@"itemImageFileName" defaultValue:@""]]; | |
[self.descriptions addObject:[BT_strings getJsonPropertyValue:thisMenuItem.jsonVars nameOfProperty:@"titleText" defaultValue:@""]]; | |
[thisMenuItem release]; | |
} | |
} | |
//layout screen | |
[self layoutScreen]; | |
} | |
}@catch (NSException * e) { | |
//delete bogus data, show alert | |
[BT_fileManager deleteFile:[self saveAsFileName]]; | |
[self showAlert:NSLocalizedString(@"errorTitle",@"~ Error ~") theMessage:NSLocalizedString(@"appParseError", @"There was a problem parsing some configuration data. Please make sure that it is well-formed")alertTag:0]; | |
[BT_debugger showIt:self theMessage:[NSString stringWithFormat:@"error parsing screen data: %@", e]]; | |
} | |
} | |
#pragma - mark iCarousel Delegate | |
//numberOfItemsInCarousel... | |
-(NSUInteger)numberOfItemsInCarousel:(iCarousel *)carousel{ | |
[BT_debugger showIt:self theMessage:@"numberOfItemsInCarousel"]; | |
return [self.AKAlbums count]; | |
} | |
//numberOfVisibleItemsInCarousel... | |
-(NSUInteger)numberOfVisibleItemsInCarousel:(iCarousel *)carousel{ | |
[BT_debugger showIt:self theMessage:@"numberOfVisibleItemsInCarousel"]; | |
return [self.AKAlbums count]; | |
} | |
//viewForItemAtIndex with reflection... | |
-(UIView*)carousel:(iCarousel *)carousel viewForItemAtIndex:(NSUInteger)index reusingView:(ReflectionView *)view{ | |
[BT_debugger showIt:self theMessage:@"viewForItemAtIndex"]; | |
UIImageView *button; | |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) | |
{ | |
//return a standard UIImageView object with the image from the array of images... | |
view = [[[ReflectionView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 200.0f, 200.0f)] autorelease]; | |
button = [[[UIImageView alloc]initWithFrame:CGRectMake(0.0f, 0.0f, 200.0f, 200.0f)] autorelease]; | |
}else if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad){ | |
//return a standard UIImageView object with the image from the array of images... | |
view = [[[ReflectionView alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 400.0f, 400.0f)] autorelease]; | |
button = [[[UIImageView alloc]initWithFrame:CGRectMake(0.0f, 0.0f, 400.0f, 400.0f)] autorelease]; | |
} | |
[view addSubview:button]; | |
button.image= [UIImage imageNamed:[AKAlbums objectAtIndex:index]]; | |
if (aCarousel.vertical == 1 | aCarousel.type == iCarouselTypeWheel | aCarousel.type == iCarouselTypeInvertedWheel | aCarousel.type == iCarouselTypeInvertedRotary) | |
{ | |
view.reflectionAlpha = 0; | |
view.reflectionScale = 0; | |
}else{ | |
view.reflectionGap = [[BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:@"AKGap" defaultValue:@"4"]floatValue]; | |
view.reflectionAlpha = [[BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:@"AKOpacity" defaultValue:@"0.5"]floatValue]; | |
view.reflectionScale = [[BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:@"AKScale" defaultValue:@"0.5"]floatValue]; | |
} | |
[view update]; | |
return view; | |
} | |
//carouselItemWidth... | |
-(CGFloat)carouselItemWidth:(iCarousel *)carousel{ | |
//[BT_debugger showIt:self:@"carouselItemWidth"]; | |
//This needs to be wider than the image or the items have no space between them. | |
//That might be a desirable effect in some instances. | |
int imagewidth; | |
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone){ | |
imagewidth = [[BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:@"iCarouselImageWidth" defaultValue:@"200"]intValue]; | |
} else { | |
imagewidth = ([[BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:@"iCarouselImageWidth" defaultValue:@"200"]intValue]*2); | |
} | |
return imagewidth; | |
} | |
//carouselShouldWrap... | |
-(BOOL)carouselShouldWrap:(iCarousel *)carousel{ | |
//[BT_debugger showIt:self:@"carouselShouldWrap"]; | |
return self.wrap; | |
} | |
//carouselDidScroll... | |
-(void)carouselDidScroll:(iCarousel *)carousel{ | |
//[BT_debugger showIt:self:@"carouselDidScroll"]; | |
[label setText:[NSString stringWithFormat:@"%@", [descriptions objectAtIndex:carousel.currentItemIndex]]]; | |
} | |
//didSelectItemAtIndex... | |
-(void)carousel:(iCarousel *)carousel didSelectItemAtIndex:(NSInteger)index{ | |
[BT_debugger showIt:self theMessage:@"didSelectItemAtIndex"]; | |
//get the BT_item that was tapped (the carousel item)... | |
BT_item *theTappedCarouselItem = [self.menuItems objectAtIndex:index]; | |
if([theTappedCarouselItem jsonVars] != nil){ | |
//get possible itemId of the screen to load | |
NSString *loadScreenItemId = [BT_strings getJsonPropertyValue:theTappedCarouselItem.jsonVars nameOfProperty:@"loadScreenWithItemId" defaultValue:@""]; | |
//get possible nickname of the screen to load | |
NSString *loadScreenNickname = [BT_strings getJsonPropertyValue:theTappedCarouselItem.jsonVars nameOfProperty:@"loadScreenWithNickname" defaultValue:@""]; | |
//bail if load screen = "none" | |
if([loadScreenItemId isEqualToString:@"none"]){ | |
return; | |
} | |
//check for loadScreenWithItemId THEN loadScreenWithNickname THEN loadScreenObject | |
BT_item *screenObjectToLoad = nil; | |
if([loadScreenItemId length] > 1){ | |
screenObjectToLoad = [appDelegate.rootApp getScreenDataByItemId:loadScreenItemId]; | |
}else{ | |
if([loadScreenNickname length] > 1){ | |
screenObjectToLoad = [appDelegate.rootApp getScreenDataByNickname:loadScreenNickname]; | |
}else{ | |
if([theTappedCarouselItem.jsonVars objectForKey:@"loadScreenObject"]){ | |
screenObjectToLoad = [[BT_item alloc] init]; | |
[screenObjectToLoad setItemId:[[theTappedCarouselItem.jsonVars objectForKey:@"loadScreenObject"] objectForKey:@"itemId"]]; | |
[screenObjectToLoad setItemNickname:[[theTappedCarouselItem.jsonVars objectForKey:@"loadScreenObject"] objectForKey:@"itemNickname"]]; | |
[screenObjectToLoad setItemType:[[theTappedCarouselItem.jsonVars objectForKey:@"loadScreenObject"] objectForKey:@"itemType"]]; | |
[screenObjectToLoad setJsonVars:[theTappedCarouselItem.jsonVars objectForKey:@"loadScreenObject"]]; | |
} | |
} | |
} | |
//load next screen if it's not nil | |
if(screenObjectToLoad != nil){ | |
[self handleTapToLoadScreen:screenObjectToLoad theMenuItemData:theTappedCarouselItem]; | |
[self stopScrolling]; | |
}else{ | |
//show message | |
[BT_debugger showIt:self theMessage:@"didSelectItemAtIndex (1): the application doesn't know how to handle this item tap?"]; | |
} | |
}else{ | |
//show message | |
[BT_debugger showIt:self theMessage:@"didSelectItemAtIndex (2): the application doesn't know how to handle this item tap?"]; | |
} | |
} | |
#pragma mark - | |
#pragma mark Autoscroll | |
- (void)startScrolling | |
{ | |
[scrollTimer invalidate]; | |
scrollTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/30.0 | |
target:self | |
selector:@selector(scrollStep) | |
userInfo:nil | |
repeats:YES]; | |
} | |
- (void)stopScrolling | |
{ | |
[scrollTimer invalidate]; | |
scrollTimer = nil; | |
} | |
- (void)scrollStep | |
{ | |
//calculate delta time | |
NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate]; | |
float delta = lastTime - now; | |
lastTime = now; | |
//don't autoscroll when user is manipulating carousel | |
if (!aCarousel.dragging && !aCarousel.decelerating) | |
{ | |
//scroll carousel | |
aCarousel.scrollOffset += delta * (float)([[BT_strings getJsonPropertyValue:self.screenData.jsonVars nameOfProperty:@"AKAutoRotate" defaultValue:@"0"]floatValue]); | |
} | |
} | |
//layoutScreen... | |
-(void)layoutScreen{ | |
[BT_debugger showIt:self theMessage:@"layoutScreen"]; | |
//reload the carousel data... | |
[aCarousel reloadData]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment