Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[ios, osx] Split MGLDirectionFormatter in two
Browse files Browse the repository at this point in the history
Split MGLDirectionFormatter into MGLClockDirectionFormatter, which specializes in clock positions, and MGLCompassDirectionFormatter, which boxes the compass. This neatly avoids any confusion that might arise if the developer fails to read the documentation and thinks the original unified formatter can convert between the two types of directions.
  • Loading branch information
1ec5 committed Apr 22, 2016
1 parent e5c6cfd commit 2a1a5f0
Show file tree
Hide file tree
Showing 12 changed files with 278 additions and 205 deletions.
4 changes: 2 additions & 2 deletions .jazzy.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ custom_categories:
- NSValue(MGLOfflinePackAdditions)
- name: Geometry
children:
- MGLClockDirectionFormatter
- MGLCompassDirectionFormatter
- MGLCoordinateBounds
- MGLCoordinateBoundsEqualToCoordinateBounds
- MGLCoordinateBoundsGetCoordinateSpan
Expand All @@ -69,8 +71,6 @@ custom_categories:
- MGLCoordinateSpanMake
- MGLCoordinateSpanZero
- MGLDegreesFromRadians
- MGLDirectionFormatter
- MGLDirectionFormatterOrigin
- MGLRadiansFromDegrees
- MGLStringFromCoordinateBounds
- NSValue(MGLGeometryAdditions)
52 changes: 52 additions & 0 deletions platform/darwin/include/MGLClockDirectionFormatter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>

#import "MGLTypes.h"

NS_ASSUME_NONNULL_BEGIN

/**
The `MGLClockDirectionFormatter` class provides properly formatted descriptions
of headings relative to the user, known as <i>clock positions</i>. For
example, a value of `90` may be formatted as “3 o’clock”, depending on the
locale.
Use this class to create localized heading strings when displaying directions
relative to the user’s current location and heading. To format a direction
irrespective of the user’s orientation, use `MGLCompassDirectionFormatter`
instead.
*/
@interface MGLClockDirectionFormatter : NSFormatter

/**
The unit style used by this formatter.
This property defaults to `NSFormattingUnitStyleMedium`.
*/
@property (nonatomic) NSFormattingUnitStyle unitStyle;

/**
The locale of the receiver.
The locale determines the output language and numeral system of the output.
*/
@property (copy) NSLocale *locale;

/**
Returns a clock position string for the provided value.
@param direction The heading, measured in degrees, where 0° means “straight
ahead” and 90° means “directly to your right”.
@return The clock position string appropriately formatted for the receiver’s
locale.
*/
- (NSString *)stringFromDirection:(CLLocationDirection)direction;

/**
This method is not supported for the `MGLDirectionFormatter` class.

This comment has been minimized.

Copy link
@incanus

incanus Aug 5, 2016

Contributor

Should this name this exact class instead? @1ec5

This comment has been minimized.

Copy link
@1ec5

1ec5 Aug 5, 2016

Author Contributor

Good catch!

*/
- (BOOL)getObjectValue:(out id __nullable * __nullable)obj forString:(NSString *)string errorDescription:(out NSString * __nullable * __nullable)error;

@end

NS_ASSUME_NONNULL_END
42 changes: 42 additions & 0 deletions platform/darwin/include/MGLCompassDirectionFormatter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#import <Foundation/Foundation.h>
#import <CoreLocation/CoreLocation.h>

#import "MGLTypes.h"

NS_ASSUME_NONNULL_BEGIN

/**
The `MGLCompassDirectionFormatter` class provides properly formatted
descriptions of absolute headings. For example, a value of `90` may be
formatted as “east”, depending on the locale.
Use this class to create localized heading strings when displaying directions
irrespective of the user’s current location. To format a direction relative to
the user’s current location, use `MGLCompassDirectionFormatter` instead.
*/
@interface MGLCompassDirectionFormatter : NSFormatter

/**
The unit style used by this formatter.
This property defaults to `NSFormattingUnitStyleMedium`.
*/
@property (nonatomic) NSFormattingUnitStyle unitStyle;

/**
Returns a heading string for the provided value.
@param direction The heading, measured in degrees, where 0° means “due north”
and 90° means “due east”.
@return The heading string appropriately formatted for the formatter’s locale.
*/
- (NSString *)stringFromDirection:(CLLocationDirection)direction;

/**
This method is not supported for the `MGLDirectionFormatter` class.
*/
- (BOOL)getObjectValue:(out id __nullable * __nullable)obj forString:(NSString *)string errorDescription:(out NSString * __nullable * __nullable)error;

@end

NS_ASSUME_NONNULL_END
77 changes: 0 additions & 77 deletions platform/darwin/include/MGLDirectionFormatter.h

This file was deleted.

64 changes: 64 additions & 0 deletions platform/darwin/src/MGLClockDirectionFormatter.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#import "MGLClockDirectionFormatter.h"

#define wrap(value, min, max) \
(fmod((fmod((value - min), (max - min)) + (max - min)), (max - min)) + min)

@implementation MGLClockDirectionFormatter {
NSNumberFormatter *_numberFormatter;
}

- (instancetype)init {
if (self = [super init]) {
_unitStyle = NSFormattingUnitStyleMedium;
_numberFormatter = [[NSNumberFormatter alloc] init];
}
return self;
}

- (NSLocale *)locale {
return _numberFormatter.locale;
}

- (void)setLocale:(NSLocale *)locale {
_numberFormatter.locale = locale;
}

- (NSString *)stringFromDirection:(CLLocationDirection)direction {
NSInteger hour = round(-wrap(-direction, -360, 0) / 360 * 12);
NSString *format;
NSNumberFormatterStyle style = NSNumberFormatterDecimalStyle;
switch (self.unitStyle) {
case NSFormattingUnitStyleShort:
format = NSLocalizedString(@"%@:00", @"Clock position format, short style");
break;

case NSFormattingUnitStyleMedium:
format = NSLocalizedString(@"%@ o’clock", @"Clock position format, medium style");

break;

case NSFormattingUnitStyleLong:
format = NSLocalizedString(@"%@ o’clock", @"Clock position format, long style");
style = NSNumberFormatterSpellOutStyle;
break;

default:
break;
}
_numberFormatter.numberStyle = style;
return [NSString stringWithFormat:format, [_numberFormatter stringFromNumber:@(hour)]];
}

- (nullable NSString *)stringForObjectValue:(id)obj {
if (![obj isKindOfClass:[NSValue class]]) {
return nil;
}
return [self stringFromDirection:[obj doubleValue]];
}

- (BOOL)getObjectValue:(out id __nullable * __nullable)obj forString:(NSString *)string errorDescription:(out NSString * __nullable * __nullable)error {
NSAssert(NO, @"-getObjectValue:forString:errorDescription: has not been implemented");
return NO;
}

@end
Original file line number Diff line number Diff line change
@@ -1,63 +1,18 @@
#import "MGLDirectionFormatter.h"
#import "MGLCompassDirectionFormatter.h"

#define wrap(value, min, max) \
(fmod((fmod((value - min), (max - min)) + (max - min)), (max - min)) + min)

@implementation MGLDirectionFormatter {
NSNumberFormatter *_numberFormatter;
}
@implementation MGLCompassDirectionFormatter

- (instancetype)init {
if (self = [super init]) {
_unitStyle = NSFormattingUnitStyleMedium;
_numberFormatter = [[NSNumberFormatter alloc] init];
}
return self;
}

- (NSLocale *)locale {
return _numberFormatter.locale;
}

- (void)setLocale:(NSLocale *)locale {
_numberFormatter.locale = locale;
}

- (NSString *)stringFromDirection:(CLLocationDirection)direction {
if (self.origin == MGLDirectionFormatterOriginNorth) {
return [self stringFromAbsoluteDirection:direction];
} else {
return [self stringFromRelativeDirection:direction];
}
}

- (NSString *)stringFromRelativeDirection:(CLLocationDirection)direction {
NSInteger hour = round(-wrap(-direction, -360, 0) / 360 * 12);
NSString *format;
NSNumberFormatterStyle style = NSNumberFormatterDecimalStyle;
switch (self.unitStyle) {
case NSFormattingUnitStyleShort:
format = NSLocalizedString(@"%@:00", @"Relative heading format, short style");
break;

case NSFormattingUnitStyleMedium:
format = NSLocalizedString(@"%@ o’clock", @"Relative heading format, medium style");

break;

case NSFormattingUnitStyleLong:
format = NSLocalizedString(@"%@ o’clock", @"Relative heading format, long style");
style = NSNumberFormatterSpellOutStyle;
break;

default:
break;
}
_numberFormatter.numberStyle = style;
return [NSString stringWithFormat:format, [_numberFormatter stringFromNumber:@(hour)]];
}

- (NSString *)stringFromAbsoluteDirection:(CLLocationDirection)direction {
static NS_ARRAY_OF(NSString *) *shortStrings;
static NS_ARRAY_OF(NSString *) *longStrings;
static dispatch_once_t onceToken;
Expand Down Expand Up @@ -138,7 +93,7 @@ - (NSString *)stringFromAbsoluteDirection:(CLLocationDirection)direction {
NSLocalizedString(@"north by west", @"North by west, long"),
];

NSAssert(shortStrings.count == longStrings.count, @"Long and short direction string arrays must have the same size.");
NSAssert(shortStrings.count == longStrings.count, @"Long and short compass direction string arrays must have the same size.");
});

NSInteger cardinalPoint = round(wrap(direction, 0, 360) / 360 * shortStrings.count);
Expand Down
49 changes: 49 additions & 0 deletions platform/darwin/test/MGLClockDirectionFormatterTests.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#import <Mapbox/Mapbox.h>
#import <XCTest/XCTest.h>

static NSString * const MGLTestLocaleIdentifier = @"en-US";

@interface MGLClockDirectionFormatterTests : XCTestCase

@end

@implementation MGLClockDirectionFormatterTests

- (void)testClockDirections {
MGLClockDirectionFormatter *shortFormatter = [[MGLClockDirectionFormatter alloc] init];
shortFormatter.unitStyle = NSFormattingUnitStyleShort;
shortFormatter.locale = [NSLocale localeWithLocaleIdentifier:MGLTestLocaleIdentifier];

MGLClockDirectionFormatter *mediumFormatter = [[MGLClockDirectionFormatter alloc] init];
mediumFormatter.locale = [NSLocale localeWithLocaleIdentifier:MGLTestLocaleIdentifier];

MGLClockDirectionFormatter *longFormatter = [[MGLClockDirectionFormatter alloc] init];
longFormatter.unitStyle = NSFormattingUnitStyleLong;
longFormatter.locale = [NSLocale localeWithLocaleIdentifier:MGLTestLocaleIdentifier];

XCTAssertEqualObjects(@"9:00", [shortFormatter stringFromDirection:-90]);
XCTAssertEqualObjects(@"9 o’clock", [mediumFormatter stringFromDirection:-90]);
XCTAssertEqualObjects(@"nine o’clock", [longFormatter stringFromDirection:-90]);

XCTAssertEqualObjects(@"12:00", [shortFormatter stringFromDirection:0]);
XCTAssertEqualObjects(@"12 o’clock", [mediumFormatter stringFromDirection:0]);
XCTAssertEqualObjects(@"twelve o’clock", [longFormatter stringFromDirection:0]);

XCTAssertEqualObjects(@"2:00", [shortFormatter stringFromDirection:45]);
XCTAssertEqualObjects(@"2 o’clock", [mediumFormatter stringFromDirection:45]);
XCTAssertEqualObjects(@"two o’clock", [longFormatter stringFromDirection:45]);

XCTAssertEqualObjects(@"3:00", [shortFormatter stringFromDirection:90]);
XCTAssertEqualObjects(@"3 o’clock", [mediumFormatter stringFromDirection:90]);
XCTAssertEqualObjects(@"three o’clock", [longFormatter stringFromDirection:90]);

XCTAssertEqualObjects(@"6:00", [shortFormatter stringFromDirection:180]);
XCTAssertEqualObjects(@"6 o’clock", [mediumFormatter stringFromDirection:180]);
XCTAssertEqualObjects(@"six o’clock", [longFormatter stringFromDirection:180]);

XCTAssertEqualObjects(@"9:00", [shortFormatter stringFromDirection:270]);
XCTAssertEqualObjects(@"9 o’clock", [mediumFormatter stringFromDirection:270]);
XCTAssertEqualObjects(@"nine o’clock", [longFormatter stringFromDirection:270]);
}

@end
Loading

0 comments on commit 2a1a5f0

Please sign in to comment.