Commits

Bill Garrison  committed 4aeb57c

Bringing in Doug Scandrett's mods for generating more detailed relative date phrases into a branch for posterity.

  • Participants
  • Parent commits 6201b86
  • Branches more-detailed-datephrase-generation

Comments (0)

Files changed (7)

File Example/RelativeDateDemo.xcodeproj/project.pbxproj

 		F2A33B3C12AD9CA400459019 /* SORelativeDateTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SORelativeDateTransformer.m; path = ../SORelativeDateTransformer/SORelativeDateTransformer.m; sourceTree = "<group>"; };
 		F2A33B3D12AD9CA400459019 /* TesterViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TesterViewController.h; sourceTree = "<group>"; };
 		F2A33B3E12AD9CA400459019 /* TesterViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TesterViewController.m; sourceTree = "<group>"; };
-		F2CD10CF166401CA004A81F3 /* README.markdown */ = {isa = PBXFileReference; lastKnownFileType = text; name = README.markdown; path = ../README.markdown; sourceTree = "<group>"; };
+		F2CD10CF166401CA004A81F3 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = text; name = README.md; path = ../README.md; sourceTree = "<group>"; };
 		F2CD10D1166402F8004A81F3 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 			isa = PBXGroup;
 			children = (
 				DAD012DB16C8311E00AF7B51 /* SORelativeDateTransformer.bundle */,
-				F2CD10CF166401CA004A81F3 /* README.markdown */,
+				F2CD10CF166401CA004A81F3 /* README.md */,
 				F2A33B3B12AD9CA400459019 /* SORelativeDateTransformer.h */,
 				F2A33B3C12AD9CA400459019 /* SORelativeDateTransformer.m */,
 				F2A33B3412AD9C7C00459019 /* Tester App Source */,

File Example/TesterViewController.h

 }
 
 - (IBAction) datePickerChangedValue:(id)sender;
+- (IBAction) relativeDepthChangeValue:(UISegmentedControl *)sender;
 
 @end
 

File Example/TesterViewController.m

 	[relativeDateLabel setText: [relativeDateTransformer transformedValue:[datePicker date]]];
 }
 
+- (IBAction) relativeDepthChangeValue:(UISegmentedControl *)sender
+{
+    relativeDateTransformer.relativeTransformDepth = (RelativeTransformDepth)sender.selectedSegmentIndex;
+    // update UI
+    [relativeDateLabel setText: [relativeDateTransformer transformedValue:[datePicker date]]];
+}
+
 @end

File Example/en.lproj/TesterViewController.xib

 <archive type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="8.00">
 	<data>
 		<int key="IBDocument.SystemTarget">1280</int>
-		<string key="IBDocument.SystemVersion">12C54</string>
-		<string key="IBDocument.InterfaceBuilderVersion">2843</string>
+		<string key="IBDocument.SystemVersion">12C3006</string>
+		<string key="IBDocument.InterfaceBuilderVersion">3084</string>
 		<string key="IBDocument.AppKitVersion">1187.34</string>
 		<string key="IBDocument.HIToolboxVersion">625.00</string>
 		<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
 			<string key="NS.key.0">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
-			<string key="NS.object.0">1929</string>
+			<string key="NS.object.0">2083</string>
 		</object>
 		<array key="IBDocument.IntegratedClassDependencies">
 			<string>IBProxyObject</string>
 			<string>IBUIDatePicker</string>
 			<string>IBUILabel</string>
+			<string>IBUISegmentedControl</string>
 			<string>IBUIView</string>
 		</array>
 		<array key="IBDocument.PluginDependencies">
 						<string key="NSFrame">{{20, 334}, {280, 61}}</string>
 						<reference key="NSSuperview" ref="774585933"/>
 						<reference key="NSWindow"/>
+						<reference key="NSNextKeyView" ref="1035436030"/>
 						<object class="NSColor" key="IBUIBackgroundColor">
 							<int key="NSColorSpace">1</int>
 							<bytes key="NSRGB">MC40MDAwMDAwMDYgMC40MDAwMDAwMDYgMC40MDAwMDAwMDYAA</bytes>
 						<bool key="IBUIAdjustsFontSizeToFit">NO</bool>
 						<double key="preferredMaxLayoutWidth">275</double>
 					</object>
+					<object class="IBUISegmentedControl" id="1035436030">
+						<reference key="NSNextResponder" ref="774585933"/>
+						<int key="NSvFlags">292</int>
+						<string key="NSFrame">{{16, 410}, {290, 30}}</string>
+						<reference key="NSSuperview" ref="774585933"/>
+						<reference key="NSWindow"/>
+						<string key="NSReuseIdentifierKey">_NS:9</string>
+						<bool key="IBUIOpaque">NO</bool>
+						<string key="targetRuntimeIdentifier">IBCocoaTouchFramework</string>
+						<int key="IBSegmentControlStyle">2</int>
+						<int key="IBNumberOfSegments">3</int>
+						<int key="IBSelectedSegmentIndex">0</int>
+						<array key="IBSegmentTitles">
+							<string>First Match</string>
+							<string>Second Match</string>
+							<string>Third Match</string>
+						</array>
+						<array class="NSMutableArray" key="IBSegmentWidths">
+							<real value="0.0"/>
+							<real value="0.0"/>
+							<real value="0.0"/>
+						</array>
+						<array class="NSMutableArray" key="IBSegmentEnabledStates">
+							<boolean value="YES"/>
+							<boolean value="YES"/>
+							<boolean value="YES"/>
+						</array>
+						<array class="NSMutableArray" key="IBSegmentContentOffsets">
+							<string>{0, 0}</string>
+							<string>{0, 0}</string>
+							<string>{0, 0}</string>
+						</array>
+						<array class="NSMutableArray" key="IBSegmentImages">
+							<object class="NSNull" id="4"/>
+							<reference ref="4"/>
+							<reference ref="4"/>
+						</array>
+					</object>
 				</array>
 				<string key="NSFrame">{{0, 20}, {320, 460}}</string>
 				<reference key="NSSuperview"/>
 					</object>
 					<int key="connectionID">14</int>
 				</object>
+				<object class="IBConnectionRecord">
+					<object class="IBCocoaTouchEventConnection" key="connection">
+						<string key="label">relativeDepthChangeValue:</string>
+						<reference key="source" ref="1035436030"/>
+						<reference key="destination" ref="372490531"/>
+						<int key="IBEventType">13</int>
+					</object>
+					<int key="connectionID">16</int>
+				</object>
 			</array>
 			<object class="IBMutableOrderedSet" key="objectRecords">
 				<array key="orderedObjects">
 							<reference ref="7301982"/>
 							<reference ref="210052879"/>
 							<reference ref="1007823394"/>
+							<reference ref="1035436030"/>
 						</array>
 						<reference key="parent" ref="0"/>
 					</object>
 						<reference key="object" ref="7301982"/>
 						<reference key="parent" ref="774585933"/>
 					</object>
+					<object class="IBObjectRecord">
+						<int key="objectID">15</int>
+						<reference key="object" ref="1035436030"/>
+						<reference key="parent" ref="774585933"/>
+					</object>
 				</array>
 			</object>
 			<dictionary class="NSMutableDictionary" key="flattenedProperties">
 				<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
 				<string key="10.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
 				<string key="11.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
+				<string key="15.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
 				<string key="6.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
 				<string key="9.IBPluginDependency">com.apple.InterfaceBuilder.IBCocoaTouchPlugin</string>
 			</dictionary>
 			<nil key="activeLocalization"/>
 			<dictionary class="NSMutableDictionary" key="localizations"/>
 			<nil key="sourceID"/>
-			<int key="maxID">14</int>
+			<int key="maxID">16</int>
 		</object>
 		<object class="IBClassDescriber" key="IBDocument.Classes">
 			<array class="NSMutableArray" key="referencedPartialClassDescriptions">
 				<object class="IBPartialClassDescription">
 					<string key="className">TesterViewController</string>
 					<string key="superclassName">UIViewController</string>
-					<object class="NSMutableDictionary" key="actions">
-						<string key="NS.key.0">datePickerChangedValue:</string>
-						<string key="NS.object.0">id</string>
-					</object>
-					<object class="NSMutableDictionary" key="actionInfosByName">
-						<string key="NS.key.0">datePickerChangedValue:</string>
-						<object class="IBActionInfo" key="NS.object.0">
+					<dictionary class="NSMutableDictionary" key="actions">
+						<string key="datePickerChangedValue:">id</string>
+						<string key="relativeDepthChangeValue:">UISegmentedControl</string>
+					</dictionary>
+					<dictionary class="NSMutableDictionary" key="actionInfosByName">
+						<object class="IBActionInfo" key="datePickerChangedValue:">
 							<string key="name">datePickerChangedValue:</string>
 							<string key="candidateClassName">id</string>
 						</object>
-					</object>
+						<object class="IBActionInfo" key="relativeDepthChangeValue:">
+							<string key="name">relativeDepthChangeValue:</string>
+							<string key="candidateClassName">UISegmentedControl</string>
+						</object>
+					</dictionary>
 					<dictionary class="NSMutableDictionary" key="outlets">
 						<string key="datePicker">UIDatePicker</string>
 						<string key="relativeDateLabel">UILabel</string>
 		</object>
 		<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
 			<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS</string>
-			<real value="1536" key="NS.object.0"/>
+			<real value="1552" key="NS.object.0"/>
 		</object>
 		<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
 		<int key="IBDocument.defaultPropertyAccessControl">3</int>
-		<string key="IBCocoaTouchPluginVersion">1929</string>
+		<string key="IBCocoaTouchPluginVersion">2083</string>
 	</data>
 </archive>

File SORelativeDateTransformer/SORelativeDateTransformer.bundle/en.lproj/SORelativeDateTransformer.strings

Binary file modified.

File SORelativeDateTransformer/SORelativeDateTransformer.h

 
 #import <Foundation/Foundation.h>
 
+typedef enum {
+    FirstMatchOnly = 0,
+    IncludeSecondMatchIgnoreZero,
+    IncludeThirdMatchIgnoreZero,
+}RelativeTransformDepth;
+
 @interface SORelativeDateTransformer : NSValueTransformer
 {
 	NSCalendar *__calendar;
 	NSUInteger __unitFlags;
 	NSArray *__dateComponentSelectorNames;
+    NSMutableArray *__partialDateStrings;
 }
+@property (nonatomic) RelativeTransformDepth relativeTransformDepth;
 
 /**
 \brief Transform an NSDate into a phrase expressing the relative difference between that date and now.

File SORelativeDateTransformer/SORelativeDateTransformer.m

     __unitFlags = NSYearCalendarUnit | NSMonthCalendarUnit | NSWeekCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
     __dateComponentSelectorNames =  [[NSArray alloc] initWithObjects:@"year", @"month", @"week", @"day", @"hour", @"minute", @"second", nil];
 	
+    __partialDateStrings = [[NSMutableArray alloc] init];
+    _relativeTransformDepth = FirstMatchOnly;
+    
 	return self;
 }
 
 {
 	[__calendar release];
 	[__dateComponentSelectorNames release];
+    [__partialDateStrings release];
 	[super dealloc];
 }
 #endif
 		return SORelativeDateLocalizedString(@"now", @"label for current date-time");
 	}
 	
+    // Clear any stored values
+    [__partialDateStrings removeAllObjects];
+    
 	// Default return value is "now".
 	
 	id transformedValue = SORelativeDateLocalizedString(@"now", @"label for current date-time");
 	// Iterate the array of NSDateComponent selectors, which are sorted in decreasing order of time span: year, month, day, etc.
 	// For the first NSDateComponent time span method that returns a reasonable non-zero value, use that value to compute the relative-to-now date phrase string.
 	
-	
+	// Keep track of relative transform depth, compare against desired.
+    RelativeTransformDepth currentDepth = FirstMatchOnly;
+    BOOL isRelativePastDate;
+    
 	for (NSString *selectorName in __dateComponentSelectorNames)
 	{
 		// Invoke the NSDateComponent selector matching the current iteration, and obtain the component's value.
         
 		// Generate the langugage-friendly phrase representing the relative difference between the input date and now.
         
-		BOOL isRelativePastDate = (relativeDifference > 0); // positive values indicate a relative past date; negative values indicate a future date.
-		
-		// Use the appropriate string formatting template depending on whether the given date is a relative past or a relative future date.
+		isRelativePastDate = (relativeDifference > 0); // positive values indicate a relative past date; negative values indicate a future date.
         
-		if (isRelativePastDate) {
-			// Fetch the string format template for relative past dates from the localization file and crunch out a formatted string.
-			NSString *pastDatePhraseTemplate = SORelativeDateLocalizedString(@"formatTemplateForRelativePastDatePhrase", nil);
-			transformedValue = [NSString stringWithFormat:pastDatePhraseTemplate, relativeDifference, localizedDateComponentName];
-		} else {
-			// Fetch the string format template for relative future dates from the localization file and crunch out a formatted string.
-			NSString *futureDatePhraseTemplate = SORelativeDateLocalizedString(@"formatTemplateForRelativeFutureDatePhrase", nil);
-			transformedValue = [NSString stringWithFormat:futureDatePhraseTemplate, labs (relativeDifference), localizedDateComponentName];
-		}
-		
-		// Break from the date components iteration loop after finding the first one with a non-zero relative difference value.
-		break;
-		
+        // if current depth is not further than expected, collect value pair
+        if (self.relativeTransformDepth >= currentDepth) {
+            // collect the target phrase for later use
+            NSString *template = SORelativeDateLocalizedString(@"formatTemplateSingleValuePair", nil);
+            NSString *existing = [NSString stringWithFormat:template, labs (relativeDifference), localizedDateComponentName];
+            [__partialDateStrings addObject:existing];
+            currentDepth++;
+        }
 	} // for loop
 	
-	
+    NSUInteger available = [__partialDateStrings count];
+    if (available > 0) {
+        transformedValue = [self transformForDepth:available-1
+                                            isPast:isRelativePastDate];
+    }
+        
 	return transformedValue;
 }
 
+- (NSString *)transformForDepth:(RelativeTransformDepth)currentDepth
+                         isPast:(BOOL)isRelativePastDate {
+    
+    // Use the appropriate string formatting template depending on whether the given date is a relative past or a relative future date.
+    NSMutableString *transformedValue = [NSMutableString string];
+    NSString *templateForDepth;
+    if (isRelativePastDate) {
+        // Fetch the string format template for relative past dates from the localization file and crunch out a formatted string.
+        templateForDepth = [NSString stringWithFormat:@"formatTemplateForRelativePastDatePhrase_Depth%i",currentDepth];
+    } else {
+        // Fetch the string format template for relative future dates from the localization file and crunch out a formatted string.
+        templateForDepth = [NSString stringWithFormat:@"formatTemplateForRelativeFutureDatePhrase_Depth%i",currentDepth];
+    }
+    NSString *datePhraseTemplate = SORelativeDateLocalizedString(templateForDepth, nil);
+    NSScanner *scanner = [NSScanner scannerWithString:datePhraseTemplate];
+    scanner.charactersToBeSkipped = nil;
+    NSString *target = nil;
+
+    // Scan up to the %@, append the partial, move the scanner, repeat
+    for (NSString *partialString in __partialDateStrings) {
+        [scanner scanUpToString:@"%@" intoString:&target];
+        if (!target) { // check to protect against %@ at the beginning of template
+            target = @"";
+        }
+        target = [target stringByAppendingString:partialString];
+        [scanner setScanLocation:scanner.scanLocation+2];
+        [transformedValue appendString:target];
+    }
+    if (!scanner.isAtEnd) {
+        [scanner scanUpToString:@"________fin__" intoString:&target];
+        if (target) {
+            [transformedValue appendString:target];
+        }
+    }
+    return transformedValue;
+}
+
 
 @end