Adds meta string to monster cards.

Implements meta method in Monster to return a formatted meta string.
Adds size to edit monster.
Moves monster copy logic to copyFromMonster in the Monster class.
Fixes JSON parsing to set strings to an empty string if they're missing from the json blob.
Makes Monster.size default to an empty string instead of null.
Cleans up some raw strings to use NSLocalizedString instead.
This commit is contained in:
2020-09-12 03:08:10 -07:00
parent dd05b39ea9
commit ee9994c2c8
9 changed files with 91 additions and 10 deletions

View File

@@ -190,7 +190,20 @@
<view key="view" contentMode="scaleToFill" id="skY-EN-baw"> <view key="view" contentMode="scaleToFill" id="skY-EN-baw">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/> <rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pZa-ia-7UT">
<rect key="frame" x="8" y="96" width="398" height="14.5"/>
<fontDescription key="fontDescription" type="system" pointSize="12"/>
<color key="textColor" systemColor="secondaryLabelColor" red="0.23529411759999999" green="0.23529411759999999" blue="0.26274509800000001" alpha="0.59999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/> <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints>
<constraint firstItem="WIX-Yu-LXJ" firstAttribute="trailing" secondItem="pZa-ia-7UT" secondAttribute="trailing" constant="8" id="8F1-nO-xrO"/>
<constraint firstItem="pZa-ia-7UT" firstAttribute="leading" secondItem="WIX-Yu-LXJ" secondAttribute="leading" constant="8" id="9Yo-N3-VeP"/>
<constraint firstItem="pZa-ia-7UT" firstAttribute="top" secondItem="WIX-Yu-LXJ" secondAttribute="top" constant="8" id="GZ7-bL-EbS"/>
</constraints>
<viewLayoutGuide key="safeArea" id="WIX-Yu-LXJ"/> <viewLayoutGuide key="safeArea" id="WIX-Yu-LXJ"/>
</view> </view>
<navigationItem key="navigationItem" id="U0U-wB-eVJ"> <navigationItem key="navigationItem" id="U0U-wB-eVJ">
@@ -200,6 +213,9 @@
</connections> </connections>
</barButtonItem> </barButtonItem>
</navigationItem> </navigationItem>
<connections>
<outlet property="monsterMeta" destination="pZa-ia-7UT" id="QEV-cs-IEk"/>
</connections>
</viewController> </viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="lvO-c7-FKV" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="lvO-c7-FKV" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects> </objects>
@@ -276,7 +292,7 @@
</scene> </scene>
</scenes> </scenes>
<inferredMetricsTieBreakers> <inferredMetricsTieBreakers>
<segue reference="Ob1-Gh-ZDQ"/> <segue reference="W6E-7q-Wzb"/>
</inferredMetricsTieBreakers> </inferredMetricsTieBreakers>
<resources> <resources>
<image name="book.fill" catalog="system" width="128" height="100"/> <image name="book.fill" catalog="system" width="128" height="100"/>

View File

@@ -63,6 +63,8 @@ NS_ASSUME_NONNULL_BEGIN
-(id)initWithJSONString:(NSString*)jsonString andContext:(NSManagedObjectContext*)context; -(id)initWithJSONString:(NSString*)jsonString andContext:(NSManagedObjectContext*)context;
-(id)initWithJSONData:(NSData*)jsonData andContext:(NSManagedObjectContext*)context; -(id)initWithJSONData:(NSData*)jsonData andContext:(NSManagedObjectContext*)context;
-(id)initWithMonster:(Monster*)monster; -(id)initWithMonster:(Monster*)monster;
-(void)copyFromMonster:(Monster*)monster;
-(NSString*)meta; -(NSString*)meta;
-(int)abilityScoreForAbilityScoreName: (NSString*)abilityScoreName; -(int)abilityScoreForAbilityScoreName: (NSString*)abilityScoreName;
-(int)abilityModifierForAbilityScoreName: (NSString*)abilityScoreName; -(int)abilityModifierForAbilityScoreName: (NSString*)abilityScoreName;

View File

@@ -7,6 +7,7 @@
// //
#import "Monster.h" #import "Monster.h"
#import "StringHelper.h"
@implementation Monster @implementation Monster
@@ -54,6 +55,7 @@
self = [super init]; self = [super init];
self.name = @""; self.name = @"";
self.size = @"";
return self; return self;
} }
@@ -69,7 +71,8 @@
NSDictionary *jsonRoot = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil]; NSDictionary *jsonRoot = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:nil];
self.name = [jsonRoot objectForKey:@"name"]; self.name = [jsonRoot objectForKey:@"name"] ?: @"";
self.size = [jsonRoot objectForKey:@"size"] ?: @"";
return self; return self;
} }
@@ -83,7 +86,26 @@
} }
-(NSString*)meta { -(NSString*)meta {
@throw [[NSException alloc] initWithName:@"unimplemented" reason:@"Method not implemented." userInfo:nil]; //"${size} ${type} (${subtype}) ${alignment}"
NSMutableArray *parts = [NSMutableArray arrayWithCapacity:4];
if (![StringHelper isStringNilOrEmpty:self.size]) {
[parts addObject:self.size];
}
if (![StringHelper isStringNilOrEmpty:self.type]) {
[parts addObject:self.type];
}
if (![StringHelper isStringNilOrEmpty:self.subtype]) {
[parts addObject:[NSString stringWithFormat:@"(%@)", self.subtype]];
}
if (![StringHelper isStringNilOrEmpty:self.alignment]) {
[parts addObject:self.alignment];
}
return [parts componentsJoinedByString:@" "];
} }
-(int)abilityScoreForAbilityScoreName: (NSString*)abilityScoreName { -(int)abilityScoreForAbilityScoreName: (NSString*)abilityScoreName {
@@ -309,4 +331,9 @@
@throw [[NSException alloc] initWithName:@"unimplemented" reason:@"Method not implemented." userInfo:nil]; @throw [[NSException alloc] initWithName:@"unimplemented" reason:@"Method not implemented." userInfo:nil];
} }
-(void)copyFromMonster:(Monster*)monster {
self.name = monster.name;
self.size = monster.size;
}
@end @end

View File

@@ -3,7 +3,7 @@
<entity name="Monster" representedClassName="Monster" syncable="YES" codeGenerationType="category"> <entity name="Monster" representedClassName="Monster" syncable="YES" codeGenerationType="category">
<attribute name="alignment" optional="YES" attributeType="String"/> <attribute name="alignment" optional="YES" attributeType="String"/>
<attribute name="name" attributeType="String" defaultValueString=""/> <attribute name="name" attributeType="String" defaultValueString=""/>
<attribute name="size" optional="YES" attributeType="String"/> <attribute name="size" optional="YES" attributeType="String" defaultValueString=""/>
<attribute name="subtype" optional="YES" attributeType="String"/> <attribute name="subtype" optional="YES" attributeType="String"/>
<attribute name="type" optional="YES" attributeType="String"/> <attribute name="type" optional="YES" attributeType="String"/>
</entity> </entity>

View File

@@ -41,7 +41,7 @@
[_context rollback]; [_context rollback];
} else if ([@"SaveChanges" isEqualToString:segue.identifier]) { } else if ([@"SaveChanges" isEqualToString:segue.identifier]) {
// TODO: this should use a method on originalMonster to copy values from editingMonster or pass the new monster back some way. Core Data would save and probably trigger a refresh in the receiving view. // TODO: this should use a method on originalMonster to copy values from editingMonster or pass the new monster back some way. Core Data would save and probably trigger a refresh in the receiving view.
self.originalMonster.name = self.editingMonster.name; [self.originalMonster copyFromMonster:self.editingMonster];
[_context refreshObject:self.editingMonster mergeChanges:NO]; [_context refreshObject:self.editingMonster mergeChanges:NO];
[_context save:nil]; [_context save:nil];
} else { } else {
@@ -59,7 +59,7 @@
// * Subtype // * Subtype
// * Alignment // * Alignment
return 1; return 2;
} }
- (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath { - (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
@@ -76,9 +76,20 @@
} }
shortStringCell.delegate = self; shortStringCell.delegate = self;
shortStringCell.identifier = @"monster.name"; shortStringCell.identifier = @"monster.name";
// TODO: make these setters on EditableShortStringTableViewCell // TODO: make these use setters on EditableShortStringTableViewCell
shortStringCell.textField.text = self.editingMonster.name; shortStringCell.textField.text = self.editingMonster.name;
shortStringCell.textField.placeholder = @"Name"; shortStringCell.textField.placeholder = NSLocalizedString(@"Name", @"Placeholder text for the name of a monster or NPC.");
return shortStringCell;
case 1:
shortStringCell = [self.monsterTableView dequeueReusableCellWithIdentifier:@"EditableShortString"];
if (shortStringCell == nil) {
shortStringCell = [[EditableShortStringTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"EditableShortString"];
}
shortStringCell.delegate = self;
shortStringCell.identifier = @"monster.size";
// TODO: make these use setters on EditableShortStringTableViewCell
shortStringCell.textField.text = self.editingMonster.size;
shortStringCell.textField.placeholder = NSLocalizedString(@"Size", @"Placehodler text for the size of a monster or NPC.");
return shortStringCell; return shortStringCell;
} }
break; break;
@@ -93,6 +104,8 @@
if ([@"String" isEqualToString:type]) { if ([@"String" isEqualToString:type]) {
if ([@"monster.name" isEqualToString:identifier]) { if ([@"monster.name" isEqualToString:identifier]) {
self.editingMonster.name = (NSString*)value; self.editingMonster.name = (NSString*)value;
} else if ([@"monster.size" isEqualToString:identifier]) {
self.editingMonster.size = (NSString*)value;
} }
} }
} }

View File

@@ -34,7 +34,7 @@
- (IBAction)addNewMonster:(id)sender { - (IBAction)addNewMonster:(id)sender {
Monster *monster = [[Monster alloc] initWithContext:_context]; Monster *monster = [[Monster alloc] initWithContext:_context];
monster.name = @"Unnamed Monster"; monster.name = NSLocalizedString(@"Unnamed Monster", @"The default name of a new monster.");
self.allMonsters = [self.allMonsters arrayByAddingObject:monster]; self.allMonsters = [self.allMonsters arrayByAddingObject:monster];
//DispatchQueue.main.async{"code here"} //DispatchQueue.main.async{"code here"}
[_context save:nil]; [_context save:nil];

View File

@@ -14,6 +14,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface MonsterViewController : UIViewController @interface MonsterViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *monsterName; @property (weak, nonatomic) IBOutlet UILabel *monsterName;
@property (weak, nonatomic) IBOutlet UILabel *monsterMeta;
@property Monster* monster; @property Monster* monster;

View File

@@ -35,6 +35,12 @@
self.navigationItem.title = self.monster.name; self.navigationItem.title = self.monster.name;
} }
} }
NSString *metaText = self.monster.meta;
if (metaText == nil) {
self.monsterMeta.text = @"";
} else {
self.monsterMeta.text = metaText;
}
} }
- (IBAction)unwindWithSegue:(UIStoryboardSegue *)unwindSegue { - (IBAction)unwindWithSegue:(UIStoryboardSegue *)unwindSegue {

View File

@@ -25,7 +25,7 @@
- (void)setUp { - (void)setUp {
_context = nil; _context = nil;
_monster = [[Monster alloc] initWithContext:_context]; _monster = [[Monster alloc] initWithContext:_context];
_jsonString = @"{\"name\":\"Acolyte\"}"; _jsonString = @"{\"name\":\"Acolyte\",\"size\":\"large\"}";
_jsonData = [_jsonString dataUsingEncoding:NSUTF8StringEncoding]; _jsonData = [_jsonString dataUsingEncoding:NSUTF8StringEncoding];
} }
@@ -36,6 +36,7 @@
- (void)testDefaultInitializer { - (void)testDefaultInitializer {
XCTAssertNotNil(_monster); XCTAssertNotNil(_monster);
XCTAssertEqualObjects(@"", _monster.name); XCTAssertEqualObjects(@"", _monster.name);
XCTAssertEqualObjects(@"", _monster.size);
} }
- (void)testInitWithJSONString { - (void)testInitWithJSONString {
@@ -43,13 +44,22 @@
XCTAssertNotNil(_monster); XCTAssertNotNil(_monster);
XCTAssertEqualObjects(@"Acolyte", _monster.name); XCTAssertEqualObjects(@"Acolyte", _monster.name);
XCTAssertEqualObjects(@"large", _monster.size);
} }
- (void)testInitWithEmptyJSONString {
_monster = [[Monster alloc] initWithJSONString:@"{}" andContext:_context];
XCTAssertNotNil(_monster);
XCTAssertEqualObjects(@"", _monster.name);
XCTAssertEqualObjects(@"", _monster.size);
}
- (void)testInitWithJSONData { - (void)testInitWithJSONData {
_monster = [[Monster alloc] initWithJSONData:_jsonData andContext:_context]; _monster = [[Monster alloc] initWithJSONData:_jsonData andContext:_context];
XCTAssertNotNil(_monster); XCTAssertNotNil(_monster);
XCTAssertEqualObjects(@"Acolyte", _monster.name); XCTAssertEqualObjects(@"Acolyte", _monster.name);
XCTAssertEqualObjects(@"large", _monster.size);
} }
- (void)testNameGetterAndSetter { - (void)testNameGetterAndSetter {
@@ -58,4 +68,10 @@
XCTAssertEqualObjects(name, _monster.name); XCTAssertEqualObjects(name, _monster.name);
} }
- (void)testSizeGetterAndSetter {
NSString *size = @"huge";
_monster.size = size;
XCTAssertEqualObjects(size, _monster.size);
}
@end @end