Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'master' of https://github.com/omz/AppSales-Mobile

Conflicts:
	AppSalesMobile.xcodeproj/project.pbxproj
	Classes/App.m
	Classes/ReviewManager.m
  • Loading branch information...
commit 98d64906d61ab07b0ad1727636f5f64bc9400c2c 2 parents d46515e + c23bbed
@jonkean jonkean authored
View
3  .gitignore
@@ -10,4 +10,5 @@ build
*.perspectivev3
*.mode1v3
*.xcworkspacedata
-*.xcuserstate
+*.xcuserstate
+*xcuserdata*
View
32 AppSalesMobile.xcodeproj/project.pbxproj
@@ -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 /* Graphs_Highlighted@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F22984BA11DD32700067EFD2 /* Graphs_Highlighted@2x.png */; };
F22984BD11DD32700067EFD2 /* Graphs@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F22984BB11DD32700067EFD2 /* Graphs@2x.png */; };
F22984C911DD343C0067EFD2 /* 5stars_gray@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = F22984C711DD343C0067EFD2 /* 5stars_gray@2x.png */; };
@@ -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 /* Graphs_Highlighted@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Graphs_Highlighted@2x.png"; sourceTree = "<group>"; };
F22984BB11DD32700067EFD2 /* Graphs@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Graphs@2x.png"; sourceTree = "<group>"; };
F22984C711DD343C0067EFD2 /* 5stars_gray@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "5stars_gray@2x.png"; sourceTree = "<group>"; };
@@ -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 */,
@@ -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;
};
@@ -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;
};
@@ -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;
@@ -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;
View
8 Classes/App.h
@@ -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;
View
63 Classes/App.m
@@ -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];
@@ -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;
}
@@ -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) {
@@ -119,6 +163,7 @@ - (void) dealloc
[reviewsByUser release];
[allAppNames release];
[lastTimeRegionDownloaded release];
+ [recentVersion release];
[super dealloc];
}
View
40 Classes/AppCell.m
@@ -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;
@@ -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)];
@@ -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) {
@@ -82,7 +84,7 @@ - (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);
@@ -90,22 +92,38 @@ - (void)drawRect:(CGRect)rect
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
View
1  Classes/AppManager.h
@@ -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
View
4 Classes/AppManager.m
@@ -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) {
View
3  Classes/AppSalesUtils.h
@@ -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));
View
34 Classes/AppleFiscalCalendar.h
@@ -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
View
122 Classes/AppleFiscalCalendar.m
@@ -0,0 +1,122 @@
+//
+// AppleFiscalCalendar.m
+// AppSalesMobile
+//
+// Created by Tim Shadel on 4/5/11.
+// Copyright 2011 Shadel Software, Inc. All rights reserved.
+//
+
+#import "AppleFiscalCalendar.h"
+
+@implementation AppleFiscalCalendar
+
+- (id)init
+{
+ self = [super init];
+ if (self) {
+ sortedDateStrings = [[NSArray arrayWithObjects:
+ @"20080928", // Oct 2008
+ @"20081102", // Nov 2008
+ @"20081130", // Dec 2008
+ @"20081228", // Jan 2009
+ @"20090201", // Feb 2009
+ @"20090301", // Mar 2009
+ @"20090329", // Apr 2009
+ @"20090503", // May 2009
+ @"20090531", // Jun 2009
+ @"20090628", // Jul 2009
+ @"20090802", // Aug 2009
+ @"20090830", // Sep 2009
+ @"20090927", // Oct 2009
+ @"20091101", // Nov 2009
+ @"20091129", // Dec 2009
+ @"20091227", // Jan 2010
+ @"20100131", // Feb 2010
+ @"20100228", // Mar 2010
+ @"20100328", // Apr 2010
+ @"20100502", // May 2010
+ @"20100530", // Jun 2010
+ @"20100629", // Jul 2010
+ @"20100801", // Aug 2010
+ @"20100829", // Sep 2010
+ @"20100926", // Oct 2010
+ @"20101031", // Nov 2010
+ @"20101128", // Dec 2010
+ @"20101226", // Jan 2011
+ @"20110130", // Feb 2011
+ @"20110227", // Mar 2011
+ @"20110327", // Apr 2011
+ @"20110501", // May 2011
+ @"20110529", // Jun 2011
+ @"20110626", // Jul 2011
+ @"20110731", // Aug 2011
+ @"20110828", // Sep 2011
+ nil] retain];
+
+ NSMutableArray *names = [NSMutableArray arrayWithCapacity:[sortedDateStrings count]];
+ NSMutableArray *dates = [NSMutableArray arrayWithCapacity:[sortedDateStrings count]];
+
+ NSDateFormatter *dayStringParser = [[NSDateFormatter alloc] init];
+ [dayStringParser setDateFormat:@"YYYYMMdd"];
+ NSDateFormatter *sectionTitleFormatter = [NSDateFormatter new];
+ [sectionTitleFormatter setDateFormat:@"MMMM yyyy"];
+ NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
+ for (NSString *dayString in sortedDateStrings) {
+ NSDate *date = [dayStringParser dateFromString:dayString];
+ [dates addObject:date];
+
+ // Name of the fiscal month can be reliably found by the calendar month of a day 2 weeks after the fiscal month begins
+ NSDateComponents *components = [[NSDateComponents alloc] init];
+ [components setDay:14];
+ NSDate *result = [gregorian dateByAddingComponents:components toDate:date options:0];
+ [components release];
+
+ NSString *fiscalMonthName = [sectionTitleFormatter stringFromDate:result];
+ [names addObject:fiscalMonthName];
+ }
+ [gregorian release];
+ [dayStringParser release];
+ [sectionTitleFormatter release];
+ sortedFiscalMonthNames = [[NSArray arrayWithArray:names] retain];
+ sortedDates = [[NSArray arrayWithArray:dates] retain];
+ }
+ return self;
+}
+
+- (NSString *)fiscalMonthForDate:(NSDate *)requestedDate
+{
+ NSUInteger indexOfNextMonth = [sortedDates
+ indexOfObject:requestedDate
+ inSortedRange:NSMakeRange(0, [sortedDates count])
+ options:NSBinarySearchingLastEqual|NSBinarySearchingInsertionIndex
+ usingComparator:
+ ^(id obj1, id obj2){
+ // Pass the day if equals, so that we can always go back one index
+ return [obj1 compare:obj2] == NSOrderedAscending ? NSOrderedAscending : NSOrderedDescending;
+ }];
+
+ if (indexOfNextMonth > 0) {
+ return [sortedFiscalMonthNames objectAtIndex:indexOfNextMonth-1];
+ } else {
+ return nil;
+ }
+}
+
++ (AppleFiscalCalendar *)sharedFiscalCalendar
+{
+ static AppleFiscalCalendar *sharedFiscalCalendar = nil;
+ if (sharedFiscalCalendar == nil)
+ sharedFiscalCalendar = [AppleFiscalCalendar new];
+ return sharedFiscalCalendar;
+}
+
+
+- (void)dealloc
+{
+ [sortedDates release], sortedDates = nil;
+ [sortedDateStrings release], sortedDateStrings = nil;
+ [sortedFiscalMonthNames release], sortedFiscalMonthNames = nil;
+ [super dealloc];
+}
+
+@end
View
280 Classes/DaysController.m
@@ -36,37 +36,111 @@
#import "CurrencyManager.h"
#import "ReportManager.h"
#import "NSDateFormatter+SharedInstances.h"
+#import "AppleFiscalCalendar.h"
+#import "Country.h"
+#import "Entry.h"
+
+static Country *newCountry(NSString *countryName, NSMutableDictionary *countries)
+{
+ Country *country = [countries objectForKey:countryName];
+ if (!country) {
+ country = [[Country alloc] initWithName:countryName day:nil];
+ [countries setObject:country forKey:countryName];
+ [country release];
+ }
+ return country;
+}
+
+@interface DaysController ()
+@property (nonatomic, retain) UIBarButtonItem *fiscalButton;
+@property (nonatomic, retain) UIBarButtonItem *calendarButton;
+@property (nonatomic, assign) DayCalendarType calendarType;
+@end
@implementation DaysController
+@synthesize fiscalButton, calendarButton, calendarType;
+
- (id)init
{
self = [super init];
if (self) {
self.title = NSLocalizedString(@"Daily Reports",nil);
+
+ self.fiscalButton = [[[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Fiscal", nil)
+ style:UIBarButtonItemStyleBordered
+ target:self
+ action:@selector(showFiscal:)] autorelease];
+
+ self.calendarButton = [[[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Calendar", nil)
+ style:UIBarButtonItemStyleBordered
+ target:self
+ action:@selector(showCalendar:)] autorelease];
}
return self;
}
+- (void)showFiscal:(id)sender
+{
+ self.calendarType = DayCalendarTypeAppleFiscal;
+ self.navigationItem.rightBarButtonItem = self.calendarButton;
+ [[NSUserDefaults standardUserDefaults] setInteger:self.calendarType forKey:@"DayCalendarType"];
+ [[NSUserDefaults standardUserDefaults] synchronize];
+ [self reload];
+}
+
+- (void)showCalendar:(id)sender
+{
+ self.calendarType = DayCalendarTypeCalendar;
+ self.navigationItem.rightBarButtonItem = self.fiscalButton;
+ [[NSUserDefaults standardUserDefaults] setInteger:self.calendarType forKey:@"DayCalendarType"];
+ [[NSUserDefaults standardUserDefaults] synchronize];
+ [self reload];
+}
+
- (void)reload
{
self.daysByMonth = [NSMutableArray array];
+
+ self.calendarType = [[NSUserDefaults standardUserDefaults] integerForKey:@"DayCalendarType"];
+ if (self.calendarType == DayCalendarTypeCalendar) {
+ self.navigationItem.rightBarButtonItem = self.fiscalButton;
+ } else {
+ self.navigationItem.rightBarButtonItem = self.calendarButton;
+ }
+
NSSortDescriptor *dateSorter = [[[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO] autorelease];
NSArray *sortedDays = [[[ReportManager sharedManager].days allValues] sortedArrayUsingDescriptors:[NSArray arrayWithObject:dateSorter]];
- int lastMonth = -1;
- NSCalendar *calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
-
- for (Day *d in sortedDays) {
- NSDate *date = d.date;
- NSDateComponents *components = [calendar components:NSMonthCalendarUnit fromDate:date];
- int month = [components month];
- if (month != lastMonth) {
- [daysByMonth addObject:[NSMutableArray array]];
- lastMonth = month;
- }
- [[daysByMonth lastObject] addObject:d];
- }
+ if (self.calendarType == DayCalendarTypeCalendar) {
+ NSCalendar *calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
+ NSInteger lastMonth = -1;
+
+ for (Day *d in sortedDays) {
+ NSDate *date = d.date;
+ NSDateComponents *components = [calendar components:NSMonthCalendarUnit fromDate:date];
+ int month = [components month];
+ if (month != lastMonth) {
+ [self.daysByMonth addObject:[NSMutableArray array]];
+ lastMonth = month;
+ }
+ [[self.daysByMonth lastObject] addObject:d];
+ }
+ } else {
+ AppleFiscalCalendar *calendar = [AppleFiscalCalendar sharedFiscalCalendar];
+ NSString *lastMonth = nil;
+
+ for (Day *d in sortedDays) {
+ NSDate *date = d.date;
+ NSString *month = [calendar fiscalMonthForDate:date];
+ if (month && [month compare:lastMonth] != NSOrderedSame) {
+ [self.daysByMonth addObject:[NSMutableArray array]];
+ lastMonth = month;
+ }
+ [[self.daysByMonth lastObject] addObject:d];
+ }
+ }
+
[self.tableView reloadData];
}
@@ -98,6 +172,64 @@ - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEd
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
+ NSInteger count = [self.daysByMonth count];
+ if(count > 1 && indexPath.section == count){
+ static NSString *CellIdentifier = @"CellTotale";
+
+ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if(cell == nil){
+ cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
+ }
+
+ float total = 0.0;
+ for(NSArray *array in self.daysByMonth){
+ for(Day *d in array){
+ total += [d totalRevenueInBaseCurrency];
+ }
+ }
+
+ cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ cell.textLabel.text = [NSLocalizedString(@"Total: ", nil) stringByAppendingString:[[CurrencyManager sharedManager] baseCurrencyDescriptionForAmount:[NSNumber numberWithFloat:total] withFraction:YES]];
+ cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
+
+ return cell;
+ }
+
+ NSArray *selectedMonth = [self.daysByMonth objectAtIndex:indexPath.section];
+
+ BOOL onlySum = NO;
+ if(onlySum || indexPath.row == [selectedMonth count]){
+ static NSString *CellIdentifier = @"CellSubtotale";
+
+ UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
+ if(cell == nil){
+ cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:nil] autorelease];
+ }
+
+ //cell.selectionStyle = UITableViewCellSelectionStyleNone;
+ float monthTotal = 0.0;
+ for(Day *d in [self.daysByMonth objectAtIndex:indexPath.section]){
+ monthTotal += [d totalRevenueInBaseCurrency];
+ }
+
+ if(!onlySum){
+ Day *firstDayInSection = [[self.daysByMonth objectAtIndex:indexPath.section] objectAtIndex:0];
+ if (self.calendarType == DayCalendarTypeCalendar) {
+ cell.textLabel.text = [NSString stringWithFormat:@"%@:", [self.sectionTitleFormatter stringFromDate:firstDayInSection.date]];
+ } else {
+ AppleFiscalCalendar *calendar = [AppleFiscalCalendar sharedFiscalCalendar];
+ cell.textLabel.text = [calendar fiscalMonthForDate:firstDayInSection.date];
+ }
+ }else
+ cell.textLabel.text = NSLocalizedString(@"Subtotal:", nil);
+
+ cell.textLabel.font = [UIFont boldSystemFontOfSize:18];
+ cell.detailTextLabel.text = [[CurrencyManager sharedManager] baseCurrencyDescriptionForAmount:[NSNumber numberWithFloat:monthTotal] withFraction:YES];
+ cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
+
+ return cell;
+ }
+
static NSString *CellIdentifier = @"Cell";
DayCell *cell = (DayCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
@@ -124,11 +256,133 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
return cell;
}
+- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
+{
+ NSInteger count = self.daysByMonth.count;
+ count = (count > 1 ? count + 1 : 1);//total
+ return count;
+}
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
+{
+ NSInteger count = self.daysByMonth.count;
+ BOOL onlySum = NO;
+ if(count > 1 && section == count){
+ return 1;//total
+ }
+
+ if (count > 0) {
+ if(onlySum)
+ return 1;
+ if(section == count)
+ return 1;//total
+ count = [[self.daysByMonth objectAtIndex:section] count];
+ if(count > 1)
+ count++;//subtotal
+ return count;
+ }
+ return 0;
+}
+
+- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
+{
+ NSInteger count = self.daysByMonth.count;
+ if(count > 1 && section == count){
+ return NSLocalizedString(@"Total:", nil);
+ }
+
+ if (self.daysByMonth.count == 0)
+ return @"";
+
+ NSArray *sectionArray = [self.daysByMonth objectAtIndex:section];
+ if (sectionArray.count == 0)
+ return @"";
+
+ Day *firstDayInSection = [sectionArray objectAtIndex:0];
+ if (self.calendarType == DayCalendarTypeCalendar) {
+ return [self.sectionTitleFormatter stringFromDate:firstDayInSection.date];
+ } else {
+ AppleFiscalCalendar *calendar = [AppleFiscalCalendar sharedFiscalCalendar];
+ return [calendar fiscalMonthForDate:firstDayInSection.date];
+ }
+}
+
+
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int section = [indexPath section];
int row = [indexPath row];
+
+ NSString *totalRevenueKey = @"totalRevenueInBaseCurrency";
+ NSString *sumTotalRevenueKey = @"@sum.totalRevenueInBaseCurrency";
+
+ NSInteger count = [self.daysByMonth count];
+ if(count > 1 && section == count){
+ NSMutableDictionary *countries = [NSMutableDictionary dictionary];
+
+ for(NSArray *array in self.daysByMonth){
+ for(Day *d in array){
+ for(Country *c in [d children]){
+ Country *country = newCountry(c.name, countries);
+ for (Entry *e in c.entries) {
+ [country addEntry:e];
+ }
+ }
+ }
+ }
+
+ NSSortDescriptor *sorter = [[[NSSortDescriptor alloc] initWithKey:totalRevenueKey ascending:NO] autorelease];
+ NSArray *children = [[countries allValues] sortedArrayUsingDescriptors:[NSArray arrayWithObject:sorter]];
+
+ float total = [[children valueForKeyPath:sumTotalRevenueKey] floatValue];
+
+ CountriesController *countriesController = [[[CountriesController alloc] initWithStyle:UITableViewStylePlain] autorelease];
+ countriesController.totalRevenue = total;
+
+ countriesController.title = NSLocalizedString(@"All time", nil);
+ countriesController.countries = children;
+ [countriesController.tableView reloadData];
+
+ [[self navigationController] pushViewController:countriesController animated:YES];
+
+ return;
+ }
+
NSArray *selectedMonth = [self.daysByMonth objectAtIndex:section];
+
+ BOOL onlySum = NO;
+ if(onlySum || row == [selectedMonth count]){
+ NSMutableDictionary *countries = [NSMutableDictionary dictionary];
+
+ for(Day *d in selectedMonth){
+ for(Country *c in [d children]){
+ Country *country = newCountry(c.name, countries);
+ for (Entry *e in c.entries) {
+ [country addEntry:e];
+ }
+ }
+ }
+
+ NSSortDescriptor *sorter = [[[NSSortDescriptor alloc] initWithKey:totalRevenueKey ascending:NO] autorelease];
+ NSArray *children = [[countries allValues] sortedArrayUsingDescriptors:[NSArray arrayWithObject:sorter]];
+
+ float total = [[children valueForKeyPath:sumTotalRevenueKey] floatValue];
+
+ CountriesController *countriesController = [[[CountriesController alloc] initWithStyle:UITableViewStylePlain] autorelease];
+ countriesController.totalRevenue = total;
+
+ Day *firstDayInSection = [[self.daysByMonth objectAtIndex:section] objectAtIndex:0];
+ countriesController.title = [self.sectionTitleFormatter stringFromDate:firstDayInSection.date];
+ countriesController.countries = children;
+ [countriesController.tableView reloadData];
+
+ [[self navigationController] pushViewController:countriesController animated:YES];
+
+ return;
+ }
+
+
+// NSArray *selectedMonth = [self.daysByMonth objectAtIndex:section];
Day *selectedDay = [selectedMonth objectAtIndex:row];
NSArray *children = [selectedDay children];
View
11 Classes/ReportManager.m
@@ -520,7 +520,11 @@ - (void) successfullyDownloadedReport:(Day*)report {
AppManager *manager = [AppManager sharedManager];
for (Country *c in [report.countries allValues]) {
for (Entry *e in c.entries) {
- if (e.transactionType==2) { continue; } //skips IAPs in app manager, so IAPs don't duplicate reviews
+ if (e.transactionType == 2 || e.transactionType == 9) {
+ //skips IAPs in app manager, so IAPs don't duplicate reviews
+ [manager removeAppWithID:e.productIdentifier];
+ continue;
+ }
[manager createOrUpdateAppIfNeededWithID:e.productIdentifier name:e.productName];
}
}
@@ -534,6 +538,11 @@ - (void)importReport:(Day *)report
AppManager *manager = [AppManager sharedManager];
for (Country *c in [report.countries allValues]) {
for (Entry *e in c.entries) {
+ if (e.transactionType == 2 || e.transactionType == 9) {
+ //skips IAPs in app manager, so IAPs don't duplicate reviews
+ [manager removeAppWithID:e.productIdentifier];
+ continue;
+ }
[manager createOrUpdateAppIfNeededWithID:e.productIdentifier name:e.productName];
}
}
View
34 Classes/ReviewManager.m
@@ -178,7 +178,7 @@ - (void) workerDone {
}
- (void) checkIfReviewsUpToDate:(ReviewUpdateBundle*)bundle {
- NSAssert([NSThread isMainThread], nil);
+ ASSERT_IS_MAIN_THREAD();
App *app = [[AppManager sharedManager] appWithID:bundle.appID];
NSDictionary *existingReviews = app.reviewsByUser;
@@ -208,7 +208,7 @@ - (void) checkIfReviewsUpToDate:(ReviewUpdateBundle*)bundle {
// called after translating new or updated reviews
- (void) addReviews:(ReviewUpdateBundle*)bundle {
- NSAssert([NSThread isMainThread], nil);
+ ASSERT_IS_MAIN_THREAD();
App *app = [[AppManager sharedManager] appWithID:bundle.appID];
for (Review *fetchedReivew in bundle.needsUpdating) {
[app addOrReplaceReview:fetchedReivew];
@@ -217,7 +217,7 @@ - (void) addReviews:(ReviewUpdateBundle*)bundle {
}
- (void) workerThreadFetch { // called by worker threads
- NSAssert(! [NSThread isMainThread], nil);
+ ASSERT_NOT_MAIN_THREAD();
NSAutoreleasePool *outerPool = [NSAutoreleasePool new];
@try {
NSMutableURLRequest *request = [[NSMutableURLRequest new] autorelease];
@@ -241,7 +241,7 @@ - (void) workerThreadFetch { // called by worker threads
NSString *storeFrontID = storeInfo.storeFrontID;
NSString *storeFront = [storeFrontID stringByAppendingString:@"-1"];
- [headers setObject:@"iTunes/4.2 (Macintosh; U; PPC Mac OS X 10.2)" forKey:@"User-Agent"];
+ [headers setObject:@"iTunes/9.2.1 (Macintosh; Intel Mac OS X 10.5.8) AppleWebKit/533.16" forKey:@"User-Agent"];
[headers setObject:storeFront forKey:@"X-Apple-Store-Front"];
[request setAllHTTPHeaderFields:headers];
[request setCachePolicy:NSURLRequestReloadIgnoringLocalCacheData];
@@ -305,12 +305,26 @@ - (void) workerThreadFetch { // called by worker threads
NSString *date = [dateVersionSplitted objectAtIndex:1];
date = [date stringByTrimmingCharactersInSet:whitespaceCharacterSet];
reviewDate = [dateFormatter dateFromString:date];
+ if (reviewDate == nil) {
+ NSDateFormatter *usDateFormatter = [[[NSDateFormatter alloc] init] autorelease];
+ NSLocale *usLocale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en-us"] autorelease];
+ [usDateFormatter setLocale:usLocale];
+ [usDateFormatter setDateFormat:@"MMM dd, yyyy"];
+ reviewDate = [usDateFormatter dateFromString:date];
+ }
} else if (dateVersionSplitted.count == 3) {
NSString *version = [dateVersionSplitted objectAtIndex:1];
reviewVersion = [version stringByTrimmingCharactersInSet:whitespaceCharacterSet];
NSString *date = [dateVersionSplitted objectAtIndex:2];
date = [date stringByTrimmingCharactersInSet:whitespaceCharacterSet];
reviewDate = [dateFormatter dateFromString:date];
+ if (reviewDate == nil) {
+ NSDateFormatter *usDateFormatter = [[[NSDateFormatter alloc] init] autorelease];
+ NSLocale *usLocale = [[[NSLocale alloc] initWithLocaleIdentifier:@"en-us"] autorelease];
+ [usDateFormatter setLocale:usLocale];
+ [usDateFormatter setDateFormat:@"MMM dd, yyyy"];
+ reviewDate = [usDateFormatter dateFromString:date];
+ }
}
[scanner scanUpToString:@"<SetFontStyle normalStyle=\"textColor\">" intoString:NULL];
@@ -338,9 +352,7 @@ - (void) workerThreadFetch { // called by worker threads
ReviewUpdateBundle *bundle = [[[ReviewUpdateBundle alloc] initWithAppID:appID reviews:input] autorelease];
[self performSelectorOnMainThread:@selector(checkIfReviewsUpToDate:) withObject:bundle waitUntilDone:YES];
if (bundle.needsUpdating.count) {
- for (Review *fetchedReview in bundle.needsUpdating) {
- [fetchedReview updateTranslations];
- }
+ [Review updateTranslations:bundle.needsUpdating];
[self performSelectorOnMainThread:@selector(addReviews:) withObject:bundle waitUntilDone:YES];
}
}
@@ -361,7 +373,7 @@ - (void) workerThreadFetch { // called by worker threads
- (void) updateReviews {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
- NSAssert(! [NSThread isMainThread], nil);
+ ASSERT_NOT_MAIN_THREAD();
#if APPSALES_DEBUG
NSDate *start = [NSDate date];
#endif
@@ -398,7 +410,7 @@ - (void) updateReviews {
}
- (void) updateReviewDownloadProgress:(NSString*)status {
- // NSAssert([NSThread isMainThread], nil);
+ // ASSERT_IS_MAIN_THREAD();
[status retain]; // must retain first
[reviewDownloadStatus release];
reviewDownloadStatus = status;
@@ -425,7 +437,7 @@ static NSInteger numStoreReviewsComparator(id arg1, id arg2, void *arg3) {
}
- (void) downloadReviews {
- NSAssert([NSThread isMainThread], nil);
+ ASSERT_IS_MAIN_THREAD();
if (isDownloadingReviews) {
return;
}
@@ -702,7 +714,7 @@ - (void) downloadReviews {
}
- (void) finishDownloadingReviews {
- NSAssert([NSThread isMainThread], nil);
+ ASSERT_IS_MAIN_THREAD();
isDownloadingReviews = NO;
[[AppManager sharedManager] saveToDisk];
View
2  Classes/ReviewsController.m
@@ -37,7 +37,7 @@ - (void)viewDidLoad
[super viewDidLoad];
self.sortedApps = [AppManager sharedManager].allAppsSorted;
- self.tableView.rowHeight = 45;
+ self.tableView.rowHeight = 60;
self.title = NSLocalizedString(@"Reviews",nil);
UIBarButtonItem *downloadButton = [[[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Download",nil)
style:UIBarButtonItemStyleBordered
View
7 Classes/RootViewController.m
@@ -48,6 +48,7 @@
#import "ReviewManager.h"
#import "ImportExportViewController.h"
#import "UIDevice+iPad.h"
+#import "AppleFiscalCalendar.h"
@implementation RootViewController
@@ -113,6 +114,12 @@ - (void)viewWillAppear:(BOOL)animated
name:ReportManagerDownloadedWeeklyReportsNotification object:nil];
}
+- (void)viewDidAppear:(BOOL)animated
+{
+ // Pre-initialize Apple calendar here for UI responsiveness; slight, slight gain, but noticeable
+ [AppleFiscalCalendar sharedFiscalCalendar];
+}
+
- (void) viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self];
View
2  Classes/WeeksController.h
@@ -46,7 +46,7 @@
@end
-@interface WeeksController : AbstractDayOrWeekController {
+@interface WeeksController : AbstractDayOrWeekController<UIActionSheetDelegate> {
BOOL onlySum;
PrevisionReport *previsionReport;
}
View
112 Classes/WeeksController.m
@@ -38,6 +38,7 @@
#import "ReportManager.h"
#import "Country.h"
#import "NSDateFormatter+SharedInstances.h"
+#import "AppleFiscalCalendar.h"
#define BACK_GROUND_COLOR [UIColor colorWithRed:0.92 green:1.0 blue:0.92 alpha:1.0]
@@ -82,7 +83,7 @@ @implementation PrevisionWeekCell
@synthesize maxRevenue;
- (id)initWithFrame:(CGRect)frame reuseIdentifier:(NSString *)reuseIdentifier {
- if (self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]) {
+ if ((self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier])) {
UIColor *calendarBackgroundColor = [UIColor colorWithRed:0.84 green:1.0 blue:0.84 alpha:1.0];
UIView *calendarBackgroundView = [[[UIView alloc] initWithFrame:CGRectMake(0,0,45,44)] autorelease];
calendarBackgroundView.backgroundColor = calendarBackgroundColor;
@@ -130,9 +131,13 @@ - (void)setPrevisonReport:(PrevisionReport *)report {
@end
+@interface WeeksController ()
+@property (nonatomic, assign) DayCalendarType calendarType;
+@end
+
@implementation WeeksController
-@synthesize previsionReport;
+@synthesize previsionReport, calendarType;
- (id)init
{
@@ -140,10 +145,13 @@ - (id)init
if (self) {
self.title = NSLocalizedString(@"Weekly Reports",nil);
- UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Only sum", nil)
- style:UIBarButtonItemStyleBordered
- target:self
- action:@selector(onlySum:)];
+// UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Only sum", nil)
+// style:UIBarButtonItemStyleBordered
+// target:self
+// action:@selector(onlySum:)];
+// self.navigationItem.rightBarButtonItem = button;
+// [button release];
+ UIBarButtonItem *button = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(showActions:)];
self.navigationItem.rightBarButtonItem = button;
[button release];
}
@@ -156,6 +164,34 @@ - (void)onlySum:(id)sender {
[self.tableView reloadData];
}
+- (void)showActions:(id)sender {
+ NSString *otherCalendar = self.calendarType == DayCalendarTypeCalendar ? @"Use Fiscal Calendar" : @"Use Monthly Calendar";
+ UIActionSheet *actions = [[UIActionSheet alloc] initWithTitle:@""
+ delegate:self
+ cancelButtonTitle:@"Cancel"
+ destructiveButtonTitle:nil
+ otherButtonTitles:@"Show Only Sums", otherCalendar, nil];
+ [actions showInView:self.view];
+ [actions release];
+}
+
+- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
+ if (buttonIndex == actionSheet.cancelButtonIndex) {
+ return;
+ }
+ if (buttonIndex == actionSheet.firstOtherButtonIndex) {
+ [self onlySum:actionSheet];
+ return;
+ }
+ if (self.calendarType == DayCalendarTypeCalendar) {
+ [[NSUserDefaults standardUserDefaults] setInteger:DayCalendarTypeAppleFiscal forKey:@"DayCalendarType"];
+ } else {
+ [[NSUserDefaults standardUserDefaults] setInteger:DayCalendarTypeCalendar forKey:@"DayCalendarType"];
+ }
+ [[NSUserDefaults standardUserDefaults] synchronize];
+ [self reload];
+}
+
- (NSIndexPath*) adjustPathForCurrentView:(NSIndexPath*)path {
if(!onlySum && previsionReport){
if(previsionReport.newMonth)
@@ -169,6 +205,7 @@ - (NSIndexPath*) adjustPathForCurrentView:(NSIndexPath*)path {
- (void)reload
{
self.daysByMonth = [NSMutableArray array];
+ self.calendarType = [[NSUserDefaults standardUserDefaults] integerForKey:@"DayCalendarType"];
NSSortDescriptor *dateSorter = [[[NSSortDescriptor alloc] initWithKey:@"date" ascending:NO] autorelease];
NSArray *sortedWeeks = [[[ReportManager sharedManager].weeks allValues] sortedArrayUsingDescriptors:[NSArray arrayWithObject:dateSorter]];
@@ -177,27 +214,40 @@ - (void)reload
int numeberOfMonths = 0;
float max = 0;
NSCalendar *calendar = [[[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar] autorelease];
+ AppleFiscalCalendar *appleCalendar = [AppleFiscalCalendar sharedFiscalCalendar];
+ NSString *lastMonthString = nil;
+
for (Day *d in sortedWeeks) {
float revenue = [d totalRevenueInBaseCurrency];
if (revenue > max)
max = revenue;
+
NSDate *date = d.date;
- NSDateComponents *components = [calendar components:NSMonthCalendarUnit fromDate:date];
- int month = [components month];
- if (month != lastMonth) {
- if (lastMonth == -1)
- firstMonth = month;
- [daysByMonth addObject:[NSMutableArray array]];
- lastMonth = month;
- }
- [[daysByMonth lastObject] addObject:d];
+ if (self.calendarType == DayCalendarTypeCalendar) {
+ NSDateComponents *components = [calendar components:NSMonthCalendarUnit fromDate:date];
+ int month = [components month];
+ if (month != lastMonth) {
+ if (lastMonth == -1)
+ firstMonth = month;
+ [self.daysByMonth addObject:[NSMutableArray array]];
+ lastMonth = month;
+ }
+ } else {
+ NSString *monthString = [appleCalendar fiscalMonthForDate:date];
+ if (monthString && [monthString compare:lastMonthString] != NSOrderedSame) {
+ [self.daysByMonth addObject:[NSMutableArray array]];
+ lastMonthString = monthString;
+ }
+ }
+ [[self.daysByMonth lastObject] addObject:d];
+
numeberOfMonths++;
}
-
+
//Prevision
self.previsionReport = nil;
if(numeberOfMonths > 0){
- NSDate *firstDayLastWeek = ((Day *)[[daysByMonth objectAtIndex:0] objectAtIndex:0]).date;
+ NSDate *firstDayLastWeek = ((Day *)[[self.daysByMonth objectAtIndex:0] objectAtIndex:0]).date;
NSArray *sortedDays = [[[ReportManager sharedManager].days allValues] sortedArrayUsingDescriptors:[NSArray arrayWithObject:dateSorter]];
if(sortedDays.count > 0 && [((Day *)[sortedDays objectAtIndex:0]).date timeIntervalSinceDate:firstDayLastWeek] >= 691200){ //8 days
//days of the current week
@@ -242,7 +292,7 @@ - (void)reload
revenueNewWeek += [[newWeekDays objectAtIndex:i] totalRevenueInBaseCurrency];
revenueLastWeek += [[lastWeekDays objectAtIndex:i] totalRevenueInBaseCurrency];
}
- float revenue = [[[daysByMonth objectAtIndex:0] objectAtIndex:0] totalRevenueInBaseCurrency] * revenueNewWeek / revenueLastWeek;
+ float revenue = [[[self.daysByMonth objectAtIndex:0] objectAtIndex:0] totalRevenueInBaseCurrency] * revenueNewWeek / revenueLastWeek;
if(revenue > max)
max = revenue;
self.previsionReport = [[PrevisionReport new] autorelease];
@@ -357,8 +407,13 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
}
if(!onlySum){
- Day *firstDayInSection = [[self.daysByMonth objectAtIndex:section] objectAtIndex:0];
- cell.textLabel.text = [NSString stringWithFormat:@"%@:", [self.sectionTitleFormatter stringFromDate:firstDayInSection.date]];
+ Day *firstDayInSection = [[self.daysByMonth objectAtIndex:indexPath.section] objectAtIndex:0];
+ if (self.calendarType == DayCalendarTypeCalendar) {
+ cell.textLabel.text = [NSString stringWithFormat:@"%@:", [self.sectionTitleFormatter stringFromDate:firstDayInSection.date]];
+ } else {
+ AppleFiscalCalendar *calendar = [AppleFiscalCalendar sharedFiscalCalendar];
+ cell.textLabel.text = [calendar fiscalMonthForDate:firstDayInSection.date];
+ }
}else
cell.textLabel.text = NSLocalizedString(@"Subtotal:", nil);
@@ -452,7 +507,13 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
countriesController.totalRevenue = total;
Day *firstDayInSection = [[self.daysByMonth objectAtIndex:section] objectAtIndex:0];
- countriesController.title = [self.sectionTitleFormatter stringFromDate:firstDayInSection.date];
+ if (self.calendarType == DayCalendarTypeCalendar) {
+ countriesController.title = [self.sectionTitleFormatter stringFromDate:firstDayInSection.date];
+ } else {
+ AppleFiscalCalendar *calendar = [AppleFiscalCalendar sharedFiscalCalendar];
+ countriesController.title = [calendar fiscalMonthForDate:firstDayInSection.date];
+ }
+
countriesController.countries = children;
[countriesController.tableView reloadData];
@@ -546,12 +607,17 @@ - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInte
if (self.daysByMonth.count == 0)
return @"";
- NSArray *sectionArray = [daysByMonth objectAtIndex:section];
+ NSArray *sectionArray = [self.daysByMonth objectAtIndex:section];
if (sectionArray.count == 0)
return @"";
Day *firstDayInSection = [sectionArray objectAtIndex:0];
- return [self.sectionTitleFormatter stringFromDate:firstDayInSection.date];
+ if (self.calendarType == DayCalendarTypeCalendar) {
+ return [self.sectionTitleFormatter stringFromDate:firstDayInSection.date];
+ } else {
+ AppleFiscalCalendar *calendar = [AppleFiscalCalendar sharedFiscalCalendar];
+ return [calendar fiscalMonthForDate:firstDayInSection.date];
+ }
}
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
Please sign in to comment.
Something went wrong with that request. Please try again.