Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/omz/AppSales-Mobile
Browse files Browse the repository at this point in the history
Conflicts:
	AppSalesMobile.xcodeproj/project.pbxproj
	Classes/App.m
	Classes/ReviewManager.m
  • Loading branch information
jonkean committed Apr 27, 2011
2 parents d46515e + c23bbed commit 98d6490
Show file tree
Hide file tree
Showing 17 changed files with 681 additions and 77 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ build
*.perspectivev3
*.mode1v3
*.xcworkspacedata
*.xcuserstate
*.xcuserstate
*xcuserdata*
32 changes: 27 additions & 5 deletions AppSalesMobile.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@
7FEA5B40105B6CD2000A12E6 /* ReviewTemplate.html in Resources */ = {isa = PBXBuildFile; fileRef = 7FEA5B3F105B6CD2000A12E6 /* ReviewTemplate.html */; };
7FEA5B43105B6D38000A12E6 /* SingleReviewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 7FEA5B42105B6D38000A12E6 /* SingleReviewController.m */; };
7FEA5C2C105C1A57000A12E6 /* 5stars_gray.png in Resources */ = {isa = PBXBuildFile; fileRef = 7FEA5C2B105C1A57000A12E6 /* 5stars_gray.png */; };
B03E6A4D134BC34C00532893 /* AppleFiscalCalendar.m in Sources */ = {isa = PBXBuildFile; fileRef = B03E6A4C134BC34C00532893 /* AppleFiscalCalendar.m */; };
F22984BC11DD32700067EFD2 /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = F22984BA11DD32700067EFD2 /* [email protected] */; };
F22984BD11DD32700067EFD2 /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = F22984BB11DD32700067EFD2 /* [email protected] */; };
F22984C911DD343C0067EFD2 /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = F22984C711DD343C0067EFD2 /* [email protected] */; };
Expand Down Expand Up @@ -869,6 +870,8 @@
7FEA5B42105B6D38000A12E6 /* SingleReviewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SingleReviewController.m; sourceTree = "<group>"; };
7FEA5C2B105C1A57000A12E6 /* 5stars_gray.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = 5stars_gray.png; sourceTree = "<group>"; };
8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
B03E6A4B134BC34C00532893 /* AppleFiscalCalendar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppleFiscalCalendar.h; sourceTree = "<group>"; };
B03E6A4C134BC34C00532893 /* AppleFiscalCalendar.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppleFiscalCalendar.m; sourceTree = "<group>"; };
F22984BA11DD32700067EFD2 /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
F22984BB11DD32700067EFD2 /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
F22984C711DD343C0067EFD2 /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2171,6 +2174,14 @@
7F4A525A116A9F4E00FA2019 /* NSDateFormatter+SharedInstances.m */,
7FB0C4400EB97BC1005E2C45 /* NSDictionary+HTTP.h */,
7FB0C4410EB97BC1005E2C45 /* NSDictionary+HTTP.m */,
7FB0C4A90EB99D01005E2C45 /* CurrencyManager.h */,
7FB0C4AA0EB99D01005E2C45 /* CurrencyManager.m */,
B03E6A4B134BC34C00532893 /* AppleFiscalCalendar.h */,
B03E6A4C134BC34C00532893 /* AppleFiscalCalendar.m */,
34DCF08E0F0461A2009F9929 /* SFHFKeychainUtils.h */,
34DCF08D0F0461A2009F9929 /* SFHFKeychainUtils.m */,
7FE3138E1152891A004DEA7C /* ProgressHUD.h */,
7FE3138F1152891A004DEA7C /* ProgressHUD.m */,
7FE313A0115294C9004DEA7C /* NSData+Compression.h */,
7FE313A1115294C9004DEA7C /* NSData+Compression.m */,
FAED39B811E7E86E003061C4 /* NSString+UnescapeHtml.h */,
Expand Down Expand Up @@ -3128,6 +3139,7 @@
FA009F1211E93E8200242DFF /* AppManager.m in Sources */,
FA027E6E12407BF500067812 /* RegexKitLite.m in Sources */,
FAA9E92712E22BB200ADD3C9 /* AppSalesUtils.m in Sources */,
B03E6A4D134BC34C00532893 /* AppleFiscalCalendar.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -3239,16 +3251,20 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_DYNAMIC_NO_PIC = YES;
GCC_FAST_MATH = YES;
GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
GCC_OPTIMIZATION_LEVEL = 3;
GCC_PREPROCESSOR_DEFINITIONS = "NS_BLOCK_ASSERTIONS=1";
GCC_STRICT_ALIASING = YES;
GCC_VERSION = com.apple.compilers.llvmgcc42;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 3.1;
PREBINDING = YES;
IPHONEOS_DEPLOYMENT_TARGET = 4.0;
PRODUCT_NAME = AppSales;
PROVISIONING_PROFILE = "";
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Distribution;
};
Expand All @@ -3259,13 +3275,16 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_DYNAMIC_NO_PIC = YES;
GCC_FAST_MATH = YES;
GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = "APPSALES_DEBUG=1";
GCC_STRICT_ALIASING = YES;
GCC_VERSION = com.apple.compilers.llvmgcc42;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 4.0;
PREBINDING = YES;
PRODUCT_NAME = AppSales;
PROVISIONING_PROFILE = "";
SDKROOT = iphoneos;
Expand All @@ -3281,13 +3300,16 @@
CODE_SIGN_IDENTITY = "iPhone Developer";
GCC_C_LANGUAGE_STANDARD = c99;
GCC_DYNAMIC_NO_PIC = YES;
GCC_FAST_MATH = YES;
GCC_INLINES_ARE_PRIVATE_EXTERN = YES;
GCC_OPTIMIZATION_LEVEL = 3;
GCC_PREPROCESSOR_DEFINITIONS = "NS_BLOCK_ASSERTIONS=1";
GCC_STRICT_ALIASING = YES;
GCC_VERSION = com.apple.compilers.llvmgcc42;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_CHECK_SWITCH_STATEMENTS = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 3.1;
PREBINDING = YES;
IPHONEOS_DEPLOYMENT_TARGET = 4.0;
PRODUCT_NAME = AppSales;
PROVISIONING_PROFILE = "";
SDKROOT = iphoneos;
Expand Down
8 changes: 7 additions & 1 deletion Classes/App.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,21 @@
NSMutableDictionary *reviewsByUser;
NSMutableDictionary *lastTimeRegionDownloaded; // mapping of app store to NSDate of last time reviews fetched
float averageStars;
float recentStars;
NSString *recentVersion;
}

@property (readonly) NSString *appID;
@property (readonly) NSString *appName;
@property (readonly) NSString *recentVersion; // the current app version
@property (readonly) NSDictionary *reviewsByUser;
@property (readonly) NSUInteger totalReviewsCount;
@property (readonly) NSUInteger totalReviewsCount; // all reviews downloaded, for any version (current or old)
@property (readonly) NSUInteger newReviewsCount;
@property (readonly) NSUInteger recentReviewsCount; // reviews for the current app version
@property (readonly) NSUInteger newRecentReviewsCount; // freshly downloaded reviews for the current app version
@property (readonly) NSArray *allAppNames;
@property (readonly) float averageStars;
@property (readonly) float recentStars; // average stars for the current app version

- (id) initWithID:(NSString*)identifier name:(NSString*)name;
- (void) addOrReplaceReview:(Review*)review;
Expand Down
63 changes: 54 additions & 9 deletions Classes/App.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,28 @@

@implementation App

@synthesize appID, appName, reviewsByUser, averageStars;
@synthesize appID, appName, reviewsByUser, averageStars, recentStars, recentVersion;

- (void) updateAverages {
double overallSum = 0;
double mostRecentVersionSum = 0;
int mostRecentVersionCount = 0;
for (Review *r in reviewsByUser.allValues) {
overallSum += r.stars;
if (recentVersion == nil || [recentVersion compare:r.version] == NSOrderedAscending) {
[recentVersion release];
recentVersion = [r.version retain];
mostRecentVersionCount = 0;
mostRecentVersionSum = 0;
}
if ([r.version isEqualToString:recentVersion]) {
mostRecentVersionCount++;
mostRecentVersionSum += r.stars;
}
}
averageStars = overallSum / reviewsByUser.count;
recentStars = mostRecentVersionSum / mostRecentVersionCount;
}

- (id)initWithCoder:(NSCoder *)coder {
self = [super init];
Expand All @@ -25,6 +46,12 @@ - (id)initWithCoder:(NSCoder *)coder {
if (lastTimeRegionDownloaded == nil) { // backwards compatibility with older serialized objects
lastTimeRegionDownloaded = [NSMutableDictionary new];
}
if ([coder containsValueForKey:@"recentVersion"] && [coder containsValueForKey:@"recentStars"]) {
recentVersion = [[coder decodeObjectForKey:@"recentVersion"] retain];
recentStars = [coder decodeFloatForKey:@"recentStars"];
} else {
[self updateAverages]; // older serialized object
}
}
return self;
}
Expand Down Expand Up @@ -78,30 +105,47 @@ - (void)encodeWithCoder:(NSCoder *)coder
{
[coder encodeObject:appID forKey:@"appID"];
[coder encodeObject:appName forKey:@"appName"];
[coder encodeObject:reviewsByUser forKey:@"reviewsByUser"];
[coder encodeObject:allAppNames forKey:@"allAppNames"];
[coder encodeObject:lastTimeRegionDownloaded forKey:@"lastTimeRegionDownloaded"];
[coder encodeFloat:averageStars forKey:@"averageStars"];
[coder encodeObject:reviewsByUser forKey:@"reviewsByUser"];
[coder encodeObject:recentVersion forKey:@"recentVersion"];
[coder encodeFloat:recentStars forKey:@"recentStars"];
}

- (NSString *) description {
return [NSString stringWithFormat:@"App %@ (%@)", self.appName, self.appID];
return [NSString stringWithFormat:NSLocalizedString(@"App %@ (%@)", nil), self.appName, self.appID];
}

- (void) addOrReplaceReview:(Review*)review {
[reviewsByUser setObject:review forKey:review.user];

double sum = 0;
for (Review *r in reviewsByUser.allValues) {
sum += r.stars;
}
averageStars = sum / reviewsByUser.count;
[self updateAverages];
}

- (NSUInteger) totalReviewsCount {
return reviewsByUser.count;
}

- (NSUInteger) recentReviewsCount {
NSUInteger recentReviewsCount = 0;
for (Review *r in reviewsByUser.allValues) {
if ([r.version isEqualToString:recentVersion]) {
recentReviewsCount++;
}
}
return recentReviewsCount;
}

- (NSUInteger) newRecentReviewsCount {
NSUInteger newReviewsCount = 0;
for (Review *r in reviewsByUser.allValues) {
if (r.newOrUpdatedReview && [r.version isEqualToString:recentVersion]) {
newReviewsCount++;
}
}
return newReviewsCount;
}

- (NSUInteger) newReviewsCount {
NSUInteger newReviewsCount = 0;
for (Review *r in reviewsByUser.allValues) {
Expand All @@ -119,6 +163,7 @@ - (void) dealloc
[reviewsByUser release];
[allAppNames release];
[lastTimeRegionDownloaded release];
[recentVersion release];
[super dealloc];
}

Expand Down
40 changes: 29 additions & 11 deletions Classes/AppCell.m
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ @implementation AppCellView

- (id)initWithCell:(AppCell *)appCell
{
[super initWithFrame:appCell.bounds];
CGRect bounds = appCell.bounds;
bounds.size.height = 60;
[super initWithFrame:bounds];
self.backgroundColor = [UIColor whiteColor];
cell = appCell;
return self;
Expand All @@ -63,7 +65,7 @@ - (void)drawRect:(CGRect)rect
App *app = cell.app;

[[UIColor colorWithWhite:0.95 alpha:1.0] set];
CGContextFillRect(c, CGRectMake(0,0,45,44));
CGContextFillRect(c, CGRectMake(0,0,45,59));

UIImage *appIcon = [[AppIconManager sharedManager] iconForAppID:app.appID];
[appIcon drawInRect:CGRectMake(6, 7, 28, 28)];
Expand All @@ -72,7 +74,7 @@ - (void)drawRect:(CGRect)rect
[((cell.highlighted) ? [UIColor whiteColor] : [UIColor blackColor]) set];
[app.appName drawInRect:CGRectMake(50, 3, 140, 30) withFont:[UIFont boldSystemFontOfSize:17.0]];

[[UIImage imageNamed:@"5stars_gray.png"] drawInRect:CGRectMake(200, 15, 90, 15)];
[[UIImage imageNamed:@"5stars_gray.png"] drawInRect:CGRectMake(200, 8, 90, 15)];
UIImage *starsImage = [UIImage imageNamed:@"5stars.png"];
CGSize size = CGSizeMake(90,15);
if (&UIGraphicsBeginImageContextWithOptions) {
Expand All @@ -82,30 +84,46 @@ - (void)drawRect:(CGRect)rect
}
CGContextRef ctx = UIGraphicsGetCurrentContext();
[starsImage drawInRect:CGRectMake(0,0,90,15)];
float averageStars = [app averageStars];
float averageStars = [app recentStars];
float widthOfStars = 90.0 - (averageStars / 5.0) * 90.0;
[[UIColor clearColor] set];
CGContextSetBlendMode(ctx, kCGBlendModeCopy);
CGContextFillRect(ctx, CGRectMake(90 - widthOfStars, 0, widthOfStars, 15));
UIImage *averageStarsImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

[averageStarsImage drawInRect:CGRectMake(200, 15, 90, 15)];
[averageStarsImage drawInRect:CGRectMake(200, 8, 90, 15)];
//[[UIImage imageNamed:@"5stars.png"] drawInRect:CGRectMake(200, 15, 88, 15)];

if(cell.highlighted)
[[UIColor whiteColor] set];
else if(app.newReviewsCount)
else if(app.newRecentReviewsCount)
[[UIColor redColor] set];
else
[[UIColor darkGrayColor] set];

[app.recentVersion drawInRect:CGRectMake(50, 25, 140, 15) withFont:[UIFont systemFontOfSize:12.0]];
NSString *recentSummary = [NSString stringWithFormat:NSLocalizedString(@"%1.2f avg, %i reviews",nil), app.recentStars, app.recentReviewsCount];
if (app.newRecentReviewsCount) {
recentSummary = [recentSummary stringByAppendingFormat:NSLocalizedString(@" (%i new)",nil), app.newRecentReviewsCount];
}
CGSize recentSummarySize = [recentSummary sizeWithFont:[UIFont systemFontOfSize:12.0]];
[recentSummary drawInRect:CGRectMake(290-recentSummarySize.width, 40-recentSummarySize.height, recentSummarySize.width, recentSummarySize.height) withFont:[UIFont systemFontOfSize:12.0]];

int numberOfReviews = [app.reviewsByUser count];
NSString *numberOfReviewsDescription = [NSString stringWithFormat:NSLocalizedString(@"%i reviews",nil), numberOfReviews];
if (app.newReviewsCount) {
numberOfReviewsDescription = [numberOfReviewsDescription stringByAppendingFormat:NSLocalizedString(@" (%i new)",nil), app.newReviewsCount];
if(cell.highlighted)
[[UIColor whiteColor] set];
else if(app.newReviewsCount)
[[UIColor redColor] set];
else
[[UIColor lightGrayColor] set];

[@"Overall" drawInRect:CGRectMake(50, 40, 140, 15) withFont:[UIFont italicSystemFontOfSize:12.0]];
NSString *overallSummary = [NSString stringWithFormat:NSLocalizedString(@"%1.2f avg, %i reviews",nil), app.averageStars, [app.reviewsByUser count]];
if (app.newRecentReviewsCount) {
overallSummary = [overallSummary stringByAppendingFormat:NSLocalizedString(@" (%i new)",nil), app.newRecentReviewsCount];
}
[numberOfReviewsDescription drawInRect:CGRectMake(50, 25, 140, 15) withFont:[UIFont systemFontOfSize:12.0]];
CGSize overallSummarySize = [overallSummary sizeWithFont:[UIFont systemFontOfSize:12.0]];
[overallSummary drawInRect:CGRectMake(290-overallSummarySize.width, 55-overallSummarySize.height, overallSummarySize.width, overallSummarySize.height) withFont:[UIFont italicSystemFontOfSize:12.0]];
}

@end
1 change: 1 addition & 0 deletions Classes/AppManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
- (App*) appWithID:(NSString*)appID;
- (void) addApp:(App*)app;
- (BOOL) createOrUpdateAppIfNeededWithID:(NSString*)appID name:(NSString*)appName;
- (void) removeAppWithID:(NSString*)appID;
- (void) saveToDisk;

@end
4 changes: 4 additions & 0 deletions Classes/AppManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@ - (void) addApp:(App*)app {
[appsByID setObject:app forKey:app.appID];
}

- (void) removeAppWithID:(NSString*)appID {
[appsByID removeObjectForKey:appID];
}

- (BOOL) createOrUpdateAppIfNeededWithID:(NSString*)appID name:(NSString*)appName {
App *app = [self appWithID:appID];
if (app == nil) {
Expand Down
3 changes: 3 additions & 0 deletions Classes/AppSalesUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
#endif


#define ASSERT_IS_MAIN_THREAD() NSAssert([NSThread isMainThread], @"must call from main thread");
#define ASSERT_NOT_MAIN_THREAD() NSAssert([NSThread isMainThread] == false, @"do not call from main thread");

__attribute__((constructor)) // run this function run when the app loads
static void InitRandom() {
srandom(time(NULL));
Expand Down
34 changes: 34 additions & 0 deletions Classes/AppleFiscalCalendar.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// AppleFiscalCalendar.h
// AppSalesMobile
//
// Created by Tim Shadel on 4/5/11.
// Copyright 2011 Shadel Software, Inc. All rights reserved.
//

#import <Foundation/Foundation.h>

typedef enum {
DayCalendarTypeCalendar,
DayCalendarTypeAppleFiscal
} DayCalendarType;


@interface AppleFiscalCalendar : NSObject {
@private
NSArray *sortedFiscalMonthNames;
NSArray *sortedDateStrings;
NSArray *sortedDates;
}

/**
* Returns the full month name and year of the fiscal month in which the given date falls.
*/
- (NSString *)fiscalMonthForDate:(NSDate *)date;

/**
* Returns the shared instance for use anywhere fiscal date information is needed.
*/
+ (AppleFiscalCalendar *)sharedFiscalCalendar;

@end
Loading

0 comments on commit 98d6490

Please sign in to comment.