├── CONTRIBUTING.md ├── Dictionary++.xcodeproj └── project.pbxproj ├── Dictionary++ ├── Base.lproj │ ├── Launch Screen.storyboard │ └── Localizable.strings ├── Dictionary++-Info.plist ├── Dictionary++-Prefix.pch ├── Images.xcassets │ ├── AppIcon.appiconset │ │ ├── AppIcon-1024.0x1024.0.png │ │ ├── AppIcon-20.0x20.0.png │ │ ├── AppIcon-20.0x20.0@2x.png │ │ ├── AppIcon-20.0x20.0@3x.png │ │ ├── AppIcon-29.0x29.0.png │ │ ├── AppIcon-29.0x29.0@2x.png │ │ ├── AppIcon-29.0x29.0@3x.png │ │ ├── AppIcon-40.0x40.0@2x.png │ │ ├── AppIcon-40.0x40.0@3x.png │ │ ├── AppIcon-60.0x60.0@2x.png │ │ ├── AppIcon-60.0x60.0@3x.png │ │ ├── AppIcon-76.0x76.0.png │ │ ├── AppIcon-76.0x76.0@2x.png │ │ ├── AppIcon-80.0x80.0.png │ │ ├── AppIcon-83.5x83.5@2x.png │ │ └── Contents.json │ └── Contents.json ├── JPAppDelegate.h ├── JPAppDelegate.m ├── Model │ ├── DictionaryPlusPlus.xcdatamodel │ │ └── contents │ ├── Favorite.h │ ├── Favorite.m │ ├── Recent.h │ └── Recent.m ├── Screenshots │ ├── 1.png │ ├── 2.png │ └── 3.png ├── View Controllers │ ├── JPMainViewController.h │ ├── JPMainViewController.m │ ├── JPReferenceLibraryViewController.h │ ├── JPReferenceLibraryViewController.m │ ├── JPUserListViewController.h │ └── JPUserListViewController.m ├── en-AU.lproj │ ├── InfoPlist.strings │ └── Localizable.strings ├── en-GB.lproj │ ├── InfoPlist.strings │ └── Localizable.strings ├── en.lproj │ └── InfoPlist.strings └── main.m ├── LICENCE └── README.md /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions from everyone are thoroughly appreciated and welcomed! ✨ 4 | 5 | This includes code but also issues and suggestions. 6 | 7 | ## How to Contribute Code 8 | 9 | 1. First, fork the repository into your account 10 | 2. Commit your changes and push them into your fork (with meaningful commit messages describing your changes) 11 | 3. Open a [pull request into the main repo](https://github.com/josh-/DictionaryPlusPlus/pulls) 12 | 13 | More explanations and in-depth documentation about this process can be found in [the GitHub Open Source Guide](https://opensource.guide/how-to-contribute/#opening-a-pull-request). 14 | 15 | Thanks for reading, and I look forward to hearing what you have to say and seeing your code. 🙌 -------------------------------------------------------------------------------- /Dictionary++.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 03456791207859DA00D9E3A6 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 03456793207859DA00D9E3A6 /* Launch Screen.storyboard */; }; 11 | 0345679820785A5C00D9E3A6 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0345679620785A5C00D9E3A6 /* Localizable.strings */; }; 12 | 034ADC351708FE250044CB17 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 034ADC341708FE250044CB17 /* UIKit.framework */; }; 13 | 034ADC371708FE250044CB17 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 034ADC361708FE250044CB17 /* Foundation.framework */; }; 14 | 034ADC391708FE250044CB17 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 034ADC381708FE250044CB17 /* CoreGraphics.framework */; }; 15 | 034ADC3F1708FE280044CB17 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 034ADC3D1708FE280044CB17 /* InfoPlist.strings */; }; 16 | 034ADC411708FE280044CB17 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 034ADC401708FE280044CB17 /* main.m */; }; 17 | 034ADC451708FE290044CB17 /* JPAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 034ADC441708FE290044CB17 /* JPAppDelegate.m */; }; 18 | 034ADC87170955A00044CB17 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 034ADC85170955900044CB17 /* CoreData.framework */; }; 19 | 034FA6601F6E431F00210365 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 034FA65F1F6E431F00210365 /* Images.xcassets */; }; 20 | 03587D151710F18B00FA6267 /* JPMainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03587D101710F17600FA6267 /* JPMainViewController.m */; }; 21 | 03587D161710F18B00FA6267 /* JPReferenceLibraryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03587D121710F17600FA6267 /* JPReferenceLibraryViewController.m */; }; 22 | 03587D171710F18B00FA6267 /* JPUserListViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 03587D141710F17600FA6267 /* JPUserListViewController.m */; }; 23 | 03587D1D1710F1B500FA6267 /* DictionaryPlusPlus.xcdatamodel in Sources */ = {isa = PBXBuildFile; fileRef = 03587D181710F1A800FA6267 /* DictionaryPlusPlus.xcdatamodel */; }; 24 | 03587D1E1710F1B500FA6267 /* Favorite.m in Sources */ = {isa = PBXBuildFile; fileRef = 03587D1A1710F1A800FA6267 /* Favorite.m */; }; 25 | 03587D1F1710F1B500FA6267 /* Recent.m in Sources */ = {isa = PBXBuildFile; fileRef = 03587D1C1710F1A800FA6267 /* Recent.m */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 034567902078599F00D9E3A6 /* en-AU */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-AU"; path = "en-AU.lproj/InfoPlist.strings"; sourceTree = ""; }; 30 | 03456795207859EB00D9E3A6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = "Base.lproj/Launch Screen.storyboard"; sourceTree = ""; }; 31 | 0345679720785A5C00D9E3A6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = ""; }; 32 | 0345679920785A6B00D9E3A6 /* en-AU */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-AU"; path = "en-AU.lproj/Localizable.strings"; sourceTree = ""; }; 33 | 0345679B20785A8500D9E3A6 /* en-GB */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-GB"; path = "en-GB.lproj/Localizable.strings"; sourceTree = ""; }; 34 | 0345679C20785A8500D9E3A6 /* en-GB */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-GB"; path = "en-GB.lproj/InfoPlist.strings"; sourceTree = ""; }; 35 | 034ADC311708FE250044CB17 /* Dictionary++.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Dictionary++.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 36 | 034ADC341708FE250044CB17 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 37 | 034ADC361708FE250044CB17 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 38 | 034ADC381708FE250044CB17 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 39 | 034ADC3C1708FE260044CB17 /* Dictionary++-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Dictionary++-Info.plist"; sourceTree = ""; }; 40 | 034ADC3E1708FE280044CB17 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 41 | 034ADC401708FE280044CB17 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 42 | 034ADC421708FE290044CB17 /* Dictionary++-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Dictionary++-Prefix.pch"; sourceTree = ""; }; 43 | 034ADC431708FE290044CB17 /* JPAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = JPAppDelegate.h; sourceTree = ""; }; 44 | 034ADC441708FE290044CB17 /* JPAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = JPAppDelegate.m; sourceTree = ""; }; 45 | 034ADC85170955900044CB17 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 46 | 034FA65F1F6E431F00210365 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 47 | 03587D0F1710F17600FA6267 /* JPMainViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = JPMainViewController.h; path = "View Controllers/JPMainViewController.h"; sourceTree = ""; }; 48 | 03587D101710F17600FA6267 /* JPMainViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = JPMainViewController.m; path = "View Controllers/JPMainViewController.m"; sourceTree = ""; }; 49 | 03587D111710F17600FA6267 /* JPReferenceLibraryViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = JPReferenceLibraryViewController.h; path = "View Controllers/JPReferenceLibraryViewController.h"; sourceTree = ""; }; 50 | 03587D121710F17600FA6267 /* JPReferenceLibraryViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = JPReferenceLibraryViewController.m; path = "View Controllers/JPReferenceLibraryViewController.m"; sourceTree = ""; }; 51 | 03587D131710F17600FA6267 /* JPUserListViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = JPUserListViewController.h; path = "View Controllers/JPUserListViewController.h"; sourceTree = ""; }; 52 | 03587D141710F17600FA6267 /* JPUserListViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = JPUserListViewController.m; path = "View Controllers/JPUserListViewController.m"; sourceTree = ""; }; 53 | 03587D181710F1A800FA6267 /* DictionaryPlusPlus.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; name = DictionaryPlusPlus.xcdatamodel; path = Model/DictionaryPlusPlus.xcdatamodel; sourceTree = ""; }; 54 | 03587D191710F1A800FA6267 /* Favorite.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Favorite.h; path = Model/Favorite.h; sourceTree = ""; }; 55 | 03587D1A1710F1A800FA6267 /* Favorite.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Favorite.m; path = Model/Favorite.m; sourceTree = ""; }; 56 | 03587D1B1710F1A800FA6267 /* Recent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = Recent.h; path = Model/Recent.h; sourceTree = ""; }; 57 | 03587D1C1710F1A800FA6267 /* Recent.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = Recent.m; path = Model/Recent.m; sourceTree = ""; }; 58 | /* End PBXFileReference section */ 59 | 60 | /* Begin PBXFrameworksBuildPhase section */ 61 | 034ADC2E1708FE250044CB17 /* Frameworks */ = { 62 | isa = PBXFrameworksBuildPhase; 63 | buildActionMask = 2147483647; 64 | files = ( 65 | 034ADC87170955A00044CB17 /* CoreData.framework in Frameworks */, 66 | 034ADC351708FE250044CB17 /* UIKit.framework in Frameworks */, 67 | 034ADC371708FE250044CB17 /* Foundation.framework in Frameworks */, 68 | 034ADC391708FE250044CB17 /* CoreGraphics.framework in Frameworks */, 69 | ); 70 | runOnlyForDeploymentPostprocessing = 0; 71 | }; 72 | /* End PBXFrameworksBuildPhase section */ 73 | 74 | /* Begin PBXGroup section */ 75 | 034ADC281708FE250044CB17 = { 76 | isa = PBXGroup; 77 | children = ( 78 | 034ADC3A1708FE250044CB17 /* Dictionary++ */, 79 | 034ADC331708FE250044CB17 /* Frameworks */, 80 | 034ADC321708FE250044CB17 /* Products */, 81 | ); 82 | sourceTree = ""; 83 | }; 84 | 034ADC321708FE250044CB17 /* Products */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 034ADC311708FE250044CB17 /* Dictionary++.app */, 88 | ); 89 | name = Products; 90 | sourceTree = ""; 91 | }; 92 | 034ADC331708FE250044CB17 /* Frameworks */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 034ADC85170955900044CB17 /* CoreData.framework */, 96 | 034ADC341708FE250044CB17 /* UIKit.framework */, 97 | 034ADC361708FE250044CB17 /* Foundation.framework */, 98 | 034ADC381708FE250044CB17 /* CoreGraphics.framework */, 99 | ); 100 | name = Frameworks; 101 | sourceTree = ""; 102 | }; 103 | 034ADC3A1708FE250044CB17 /* Dictionary++ */ = { 104 | isa = PBXGroup; 105 | children = ( 106 | 034ADC431708FE290044CB17 /* JPAppDelegate.h */, 107 | 034ADC441708FE290044CB17 /* JPAppDelegate.m */, 108 | 0345679620785A5C00D9E3A6 /* Localizable.strings */, 109 | 03587D0D1710F14100FA6267 /* View Controllers */, 110 | 03587D0E1710F14B00FA6267 /* Model */, 111 | 034ADC3B1708FE260044CB17 /* Supporting Files */, 112 | ); 113 | path = "Dictionary++"; 114 | sourceTree = ""; 115 | }; 116 | 034ADC3B1708FE260044CB17 /* Supporting Files */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | 034FA65F1F6E431F00210365 /* Images.xcassets */, 120 | 03456793207859DA00D9E3A6 /* Launch Screen.storyboard */, 121 | 034ADC3C1708FE260044CB17 /* Dictionary++-Info.plist */, 122 | 034ADC3D1708FE280044CB17 /* InfoPlist.strings */, 123 | 034ADC401708FE280044CB17 /* main.m */, 124 | 034ADC421708FE290044CB17 /* Dictionary++-Prefix.pch */, 125 | ); 126 | name = "Supporting Files"; 127 | sourceTree = ""; 128 | }; 129 | 03587D0D1710F14100FA6267 /* View Controllers */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 03587D0F1710F17600FA6267 /* JPMainViewController.h */, 133 | 03587D101710F17600FA6267 /* JPMainViewController.m */, 134 | 03587D111710F17600FA6267 /* JPReferenceLibraryViewController.h */, 135 | 03587D121710F17600FA6267 /* JPReferenceLibraryViewController.m */, 136 | 03587D131710F17600FA6267 /* JPUserListViewController.h */, 137 | 03587D141710F17600FA6267 /* JPUserListViewController.m */, 138 | ); 139 | name = "View Controllers"; 140 | sourceTree = ""; 141 | }; 142 | 03587D0E1710F14B00FA6267 /* Model */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | 03587D181710F1A800FA6267 /* DictionaryPlusPlus.xcdatamodel */, 146 | 03587D191710F1A800FA6267 /* Favorite.h */, 147 | 03587D1A1710F1A800FA6267 /* Favorite.m */, 148 | 03587D1B1710F1A800FA6267 /* Recent.h */, 149 | 03587D1C1710F1A800FA6267 /* Recent.m */, 150 | ); 151 | name = Model; 152 | sourceTree = ""; 153 | }; 154 | /* End PBXGroup section */ 155 | 156 | /* Begin PBXNativeTarget section */ 157 | 034ADC301708FE250044CB17 /* Dictionary++ */ = { 158 | isa = PBXNativeTarget; 159 | buildConfigurationList = 034ADC4E1708FE2B0044CB17 /* Build configuration list for PBXNativeTarget "Dictionary++" */; 160 | buildPhases = ( 161 | 034ADC2D1708FE250044CB17 /* Sources */, 162 | 034ADC2E1708FE250044CB17 /* Frameworks */, 163 | 034ADC2F1708FE250044CB17 /* Resources */, 164 | ); 165 | buildRules = ( 166 | ); 167 | dependencies = ( 168 | ); 169 | name = "Dictionary++"; 170 | productName = "Dictionary++"; 171 | productReference = 034ADC311708FE250044CB17 /* Dictionary++.app */; 172 | productType = "com.apple.product-type.application"; 173 | }; 174 | /* End PBXNativeTarget section */ 175 | 176 | /* Begin PBXProject section */ 177 | 034ADC291708FE250044CB17 /* Project object */ = { 178 | isa = PBXProject; 179 | attributes = { 180 | CLASSPREFIX = JP; 181 | LastUpgradeCheck = 0930; 182 | ORGANIZATIONNAME = "Josh Parnham"; 183 | }; 184 | buildConfigurationList = 034ADC2C1708FE250044CB17 /* Build configuration list for PBXProject "Dictionary++" */; 185 | compatibilityVersion = "Xcode 3.2"; 186 | developmentRegion = English; 187 | hasScannedForEncodings = 0; 188 | knownRegions = ( 189 | en, 190 | "en-AU", 191 | Base, 192 | "en-GB", 193 | ); 194 | mainGroup = 034ADC281708FE250044CB17; 195 | productRefGroup = 034ADC321708FE250044CB17 /* Products */; 196 | projectDirPath = ""; 197 | projectRoot = ""; 198 | targets = ( 199 | 034ADC301708FE250044CB17 /* Dictionary++ */, 200 | ); 201 | }; 202 | /* End PBXProject section */ 203 | 204 | /* Begin PBXResourcesBuildPhase section */ 205 | 034ADC2F1708FE250044CB17 /* Resources */ = { 206 | isa = PBXResourcesBuildPhase; 207 | buildActionMask = 2147483647; 208 | files = ( 209 | 034FA6601F6E431F00210365 /* Images.xcassets in Resources */, 210 | 0345679820785A5C00D9E3A6 /* Localizable.strings in Resources */, 211 | 034ADC3F1708FE280044CB17 /* InfoPlist.strings in Resources */, 212 | 03456791207859DA00D9E3A6 /* Launch Screen.storyboard in Resources */, 213 | ); 214 | runOnlyForDeploymentPostprocessing = 0; 215 | }; 216 | /* End PBXResourcesBuildPhase section */ 217 | 218 | /* Begin PBXSourcesBuildPhase section */ 219 | 034ADC2D1708FE250044CB17 /* Sources */ = { 220 | isa = PBXSourcesBuildPhase; 221 | buildActionMask = 2147483647; 222 | files = ( 223 | 03587D1D1710F1B500FA6267 /* DictionaryPlusPlus.xcdatamodel in Sources */, 224 | 03587D1E1710F1B500FA6267 /* Favorite.m in Sources */, 225 | 03587D1F1710F1B500FA6267 /* Recent.m in Sources */, 226 | 03587D151710F18B00FA6267 /* JPMainViewController.m in Sources */, 227 | 03587D161710F18B00FA6267 /* JPReferenceLibraryViewController.m in Sources */, 228 | 03587D171710F18B00FA6267 /* JPUserListViewController.m in Sources */, 229 | 034ADC411708FE280044CB17 /* main.m in Sources */, 230 | 034ADC451708FE290044CB17 /* JPAppDelegate.m in Sources */, 231 | ); 232 | runOnlyForDeploymentPostprocessing = 0; 233 | }; 234 | /* End PBXSourcesBuildPhase section */ 235 | 236 | /* Begin PBXVariantGroup section */ 237 | 03456793207859DA00D9E3A6 /* Launch Screen.storyboard */ = { 238 | isa = PBXVariantGroup; 239 | children = ( 240 | 03456795207859EB00D9E3A6 /* Base */, 241 | ); 242 | name = "Launch Screen.storyboard"; 243 | sourceTree = ""; 244 | }; 245 | 0345679620785A5C00D9E3A6 /* Localizable.strings */ = { 246 | isa = PBXVariantGroup; 247 | children = ( 248 | 0345679720785A5C00D9E3A6 /* Base */, 249 | 0345679920785A6B00D9E3A6 /* en-AU */, 250 | 0345679B20785A8500D9E3A6 /* en-GB */, 251 | ); 252 | name = Localizable.strings; 253 | sourceTree = ""; 254 | }; 255 | 034ADC3D1708FE280044CB17 /* InfoPlist.strings */ = { 256 | isa = PBXVariantGroup; 257 | children = ( 258 | 034ADC3E1708FE280044CB17 /* en */, 259 | 034567902078599F00D9E3A6 /* en-AU */, 260 | 0345679C20785A8500D9E3A6 /* en-GB */, 261 | ); 262 | name = InfoPlist.strings; 263 | sourceTree = ""; 264 | }; 265 | /* End PBXVariantGroup section */ 266 | 267 | /* Begin XCBuildConfiguration section */ 268 | 034ADC4C1708FE2B0044CB17 /* Debug */ = { 269 | isa = XCBuildConfiguration; 270 | buildSettings = { 271 | ALWAYS_SEARCH_USER_PATHS = NO; 272 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 273 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 274 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 275 | CLANG_CXX_LIBRARY = "libc++"; 276 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 277 | CLANG_WARN_BOOL_CONVERSION = YES; 278 | CLANG_WARN_COMMA = YES; 279 | CLANG_WARN_CONSTANT_CONVERSION = YES; 280 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 281 | CLANG_WARN_EMPTY_BODY = YES; 282 | CLANG_WARN_ENUM_CONVERSION = YES; 283 | CLANG_WARN_INFINITE_RECURSION = YES; 284 | CLANG_WARN_INT_CONVERSION = YES; 285 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 286 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 287 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 288 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 289 | CLANG_WARN_STRICT_PROTOTYPES = YES; 290 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 291 | CLANG_WARN_UNREACHABLE_CODE = YES; 292 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 293 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 294 | COPY_PHASE_STRIP = NO; 295 | ENABLE_STRICT_OBJC_MSGSEND = YES; 296 | ENABLE_TESTABILITY = YES; 297 | GCC_C_LANGUAGE_STANDARD = gnu99; 298 | GCC_DYNAMIC_NO_PIC = NO; 299 | GCC_NO_COMMON_BLOCKS = YES; 300 | GCC_OPTIMIZATION_LEVEL = 0; 301 | GCC_PREPROCESSOR_DEFINITIONS = ( 302 | "DEBUG=1", 303 | "$(inherited)", 304 | ); 305 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 306 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 307 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 308 | GCC_WARN_UNDECLARED_SELECTOR = YES; 309 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 310 | GCC_WARN_UNUSED_FUNCTION = YES; 311 | GCC_WARN_UNUSED_VARIABLE = YES; 312 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 313 | ONLY_ACTIVE_ARCH = YES; 314 | SDKROOT = iphoneos; 315 | TARGETED_DEVICE_FAMILY = "1,2"; 316 | }; 317 | name = Debug; 318 | }; 319 | 034ADC4D1708FE2B0044CB17 /* Release */ = { 320 | isa = XCBuildConfiguration; 321 | buildSettings = { 322 | ALWAYS_SEARCH_USER_PATHS = NO; 323 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 324 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 325 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 326 | CLANG_CXX_LIBRARY = "libc++"; 327 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 328 | CLANG_WARN_BOOL_CONVERSION = YES; 329 | CLANG_WARN_COMMA = YES; 330 | CLANG_WARN_CONSTANT_CONVERSION = YES; 331 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 332 | CLANG_WARN_EMPTY_BODY = YES; 333 | CLANG_WARN_ENUM_CONVERSION = YES; 334 | CLANG_WARN_INFINITE_RECURSION = YES; 335 | CLANG_WARN_INT_CONVERSION = YES; 336 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 337 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 338 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 339 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 340 | CLANG_WARN_STRICT_PROTOTYPES = YES; 341 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 342 | CLANG_WARN_UNREACHABLE_CODE = YES; 343 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 344 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 345 | COPY_PHASE_STRIP = YES; 346 | ENABLE_STRICT_OBJC_MSGSEND = YES; 347 | GCC_C_LANGUAGE_STANDARD = gnu99; 348 | GCC_NO_COMMON_BLOCKS = YES; 349 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 350 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 351 | GCC_WARN_UNDECLARED_SELECTOR = YES; 352 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 353 | GCC_WARN_UNUSED_FUNCTION = YES; 354 | GCC_WARN_UNUSED_VARIABLE = YES; 355 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 356 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; 357 | SDKROOT = iphoneos; 358 | TARGETED_DEVICE_FAMILY = "1,2"; 359 | VALIDATE_PRODUCT = YES; 360 | }; 361 | name = Release; 362 | }; 363 | 034ADC4F1708FE2B0044CB17 /* Debug */ = { 364 | isa = XCBuildConfiguration; 365 | buildSettings = { 366 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 367 | CLANG_ENABLE_OBJC_ARC = YES; 368 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 369 | GCC_PREFIX_HEADER = "Dictionary++/Dictionary++-Prefix.pch"; 370 | INFOPLIST_FILE = "Dictionary++/Dictionary++-Info.plist"; 371 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 372 | PRODUCT_BUNDLE_IDENTIFIER = "joshparnham.${PRODUCT_NAME:rfc1034identifier}"; 373 | PRODUCT_NAME = "$(TARGET_NAME)"; 374 | WRAPPER_EXTENSION = app; 375 | }; 376 | name = Debug; 377 | }; 378 | 034ADC501708FE2B0044CB17 /* Release */ = { 379 | isa = XCBuildConfiguration; 380 | buildSettings = { 381 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 382 | CLANG_ENABLE_OBJC_ARC = YES; 383 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 384 | GCC_PREFIX_HEADER = "Dictionary++/Dictionary++-Prefix.pch"; 385 | INFOPLIST_FILE = "Dictionary++/Dictionary++-Info.plist"; 386 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 387 | PRODUCT_BUNDLE_IDENTIFIER = "joshparnham.${PRODUCT_NAME:rfc1034identifier}"; 388 | PRODUCT_NAME = "$(TARGET_NAME)"; 389 | WRAPPER_EXTENSION = app; 390 | }; 391 | name = Release; 392 | }; 393 | /* End XCBuildConfiguration section */ 394 | 395 | /* Begin XCConfigurationList section */ 396 | 034ADC2C1708FE250044CB17 /* Build configuration list for PBXProject "Dictionary++" */ = { 397 | isa = XCConfigurationList; 398 | buildConfigurations = ( 399 | 034ADC4C1708FE2B0044CB17 /* Debug */, 400 | 034ADC4D1708FE2B0044CB17 /* Release */, 401 | ); 402 | defaultConfigurationIsVisible = 0; 403 | defaultConfigurationName = Release; 404 | }; 405 | 034ADC4E1708FE2B0044CB17 /* Build configuration list for PBXNativeTarget "Dictionary++" */ = { 406 | isa = XCConfigurationList; 407 | buildConfigurations = ( 408 | 034ADC4F1708FE2B0044CB17 /* Debug */, 409 | 034ADC501708FE2B0044CB17 /* Release */, 410 | ); 411 | defaultConfigurationIsVisible = 0; 412 | defaultConfigurationName = Release; 413 | }; 414 | /* End XCConfigurationList section */ 415 | }; 416 | rootObject = 034ADC291708FE250044CB17 /* Project object */; 417 | } 418 | -------------------------------------------------------------------------------- /Dictionary++/Base.lproj/Launch Screen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /Dictionary++/Base.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | Dictionary++ 4 | 5 | Created by Josh Parnham on 7/4/18. 6 | Copyright © 2018 Josh Parnham. All rights reserved. 7 | */ 8 | 9 | "Favorite" = "Favorite"; 10 | "Unfavorite" = "Unfavorite"; 11 | "Recent" = "Recent"; 12 | "Favorites" = "Favorites"; 13 | "Done" = "Done"; 14 | -------------------------------------------------------------------------------- /Dictionary++/Dictionary++-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 2.1 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 2.1 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | Launch Screen 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UIStatusBarStyle 34 | UIStatusBarStyleDefault 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Dictionary++/Dictionary++-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'Dictionary++' target in the 'Dictionary++' project 3 | // 4 | 5 | #import 6 | 7 | #ifndef __IPHONE_3_0 8 | #warning "This project uses features only available in iOS SDK 3.0 and later." 9 | #endif 10 | 11 | #ifdef __OBJC__ 12 | #import 13 | #import 14 | #import 15 | #endif 16 | -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-1024.0x1024.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-1024.0x1024.0.png -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-20.0x20.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-20.0x20.0.png -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-20.0x20.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-20.0x20.0@2x.png -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-20.0x20.0@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-20.0x20.0@3x.png -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-29.0x29.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-29.0x29.0.png -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-29.0x29.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-29.0x29.0@2x.png -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-29.0x29.0@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-29.0x29.0@3x.png -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-40.0x40.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-40.0x40.0@2x.png -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-40.0x40.0@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-40.0x40.0@3x.png -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-60.0x60.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-60.0x60.0@2x.png -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-60.0x60.0@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-60.0x60.0@3x.png -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-76.0x76.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-76.0x76.0.png -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-76.0x76.0@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-76.0x76.0@2x.png -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-80.0x80.0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-80.0x80.0.png -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Images.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "AppIcon-20.0x20.0@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "AppIcon-20.0x20.0@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "AppIcon-29.0x29.0@2x.png", 19 | "scale" : "2x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "AppIcon-29.0x29.0@3x.png", 25 | "scale" : "3x" 26 | }, 27 | { 28 | "size" : "40x40", 29 | "idiom" : "iphone", 30 | "filename" : "AppIcon-40.0x40.0@2x.png", 31 | "scale" : "2x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "AppIcon-40.0x40.0@3x.png", 37 | "scale" : "3x" 38 | }, 39 | { 40 | "size" : "60x60", 41 | "idiom" : "iphone", 42 | "filename" : "AppIcon-60.0x60.0@2x.png", 43 | "scale" : "2x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "AppIcon-60.0x60.0@3x.png", 49 | "scale" : "3x" 50 | }, 51 | { 52 | "size" : "20x20", 53 | "idiom" : "ipad", 54 | "filename" : "AppIcon-20.0x20.0.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "AppIcon-20.0x20.0@2x.png", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "size" : "29x29", 65 | "idiom" : "ipad", 66 | "filename" : "AppIcon-29.0x29.0.png", 67 | "scale" : "1x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "AppIcon-29.0x29.0@2x.png", 73 | "scale" : "2x" 74 | }, 75 | { 76 | "size" : "40x40", 77 | "idiom" : "ipad", 78 | "filename" : "AppIcon-20.0x20.0@2x.png", 79 | "scale" : "1x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "AppIcon-80.0x80.0.png", 85 | "scale" : "2x" 86 | }, 87 | { 88 | "size" : "76x76", 89 | "idiom" : "ipad", 90 | "filename" : "AppIcon-76.0x76.0.png", 91 | "scale" : "1x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "AppIcon-76.0x76.0@2x.png", 97 | "scale" : "2x" 98 | }, 99 | { 100 | "size" : "83.5x83.5", 101 | "idiom" : "ipad", 102 | "filename" : "AppIcon-83.5x83.5@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "1024x1024", 107 | "idiom" : "ios-marketing", 108 | "filename" : "AppIcon-1024.0x1024.0.png", 109 | "scale" : "1x" 110 | } 111 | ], 112 | "info" : { 113 | "version" : 1, 114 | "author" : "xcode" 115 | } 116 | } -------------------------------------------------------------------------------- /Dictionary++/Images.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Dictionary++/JPAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // JPAppDelegate.h 3 | // Dictionary++ 4 | // 5 | // Created by Josh Parnham on 1/04/13. 6 | // Copyright (c) 2013 Josh Parnham. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JPAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext; 16 | @property (readonly, strong, nonatomic) NSManagedObjectModel *managedObjectModel; 17 | @property (readonly, strong, nonatomic) NSPersistentStoreCoordinator *persistentStoreCoordinator; 18 | 19 | - (void)saveContext; 20 | - (NSURL *)applicationDocumentsDirectory; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Dictionary++/JPAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // JPAppDelegate.m 3 | // Dictionary++ 4 | // 5 | // Created by Josh Parnham on 1/04/13. 6 | // Copyright (c) 2013 Josh Parnham. All rights reserved. 7 | // 8 | 9 | #import "JPAppDelegate.h" 10 | #import "JPMainViewController.h" 11 | 12 | @implementation JPAppDelegate 13 | 14 | 15 | @synthesize managedObjectContext = _managedObjectContext; 16 | @synthesize managedObjectModel = _managedObjectModel; 17 | @synthesize persistentStoreCoordinator = _persistentStoreCoordinator; 18 | 19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 20 | { 21 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 22 | 23 | UIColor *tintColor = [UIColor colorWithRed:0.600 green:0.400 blue:0.200 alpha:1.000]; 24 | [[UINavigationBar appearance] setTintColor:tintColor]; 25 | [[UISearchBar appearance] setTintColor:tintColor]; 26 | 27 | JPMainViewController *mainViewController = [[JPMainViewController alloc] init]; 28 | UINavigationController *mainNavigationController = [[UINavigationController alloc] initWithRootViewController:mainViewController]; 29 | 30 | self.window.rootViewController = mainNavigationController; 31 | 32 | [self.window makeKeyAndVisible]; 33 | return YES; 34 | } 35 | 36 | - (void)applicationWillResignActive:(UIApplication *)application 37 | { 38 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 39 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 40 | } 41 | 42 | - (void)applicationDidEnterBackground:(UIApplication *)application 43 | { 44 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 45 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 46 | } 47 | 48 | - (void)applicationWillEnterForeground:(UIApplication *)application 49 | { 50 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 51 | } 52 | 53 | - (void)applicationDidBecomeActive:(UIApplication *)application 54 | { 55 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 56 | } 57 | 58 | - (void)applicationWillTerminate:(UIApplication *)application 59 | { 60 | // Saves changes in the application's managed object context before the application terminates. 61 | [self saveContext]; 62 | } 63 | 64 | - (void)saveContext 65 | { 66 | NSError *error = nil; 67 | NSManagedObjectContext *managedObjectContext = self.managedObjectContext; 68 | if (managedObjectContext != nil) { 69 | if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) { 70 | // Replace this implementation with code to handle the error appropriately. 71 | // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 72 | NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 73 | abort(); 74 | } 75 | } 76 | } 77 | 78 | #pragma mark - Core Data stack 79 | 80 | // Returns the managed object context for the application. 81 | // If the context doesn't already exist, it is created and bound to the persistent store coordinator for the application. 82 | - (NSManagedObjectContext *)managedObjectContext 83 | { 84 | if (_managedObjectContext != nil) { 85 | return _managedObjectContext; 86 | } 87 | 88 | NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator]; 89 | if (coordinator != nil) { 90 | _managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 91 | [_managedObjectContext setPersistentStoreCoordinator:coordinator]; 92 | } 93 | return _managedObjectContext; 94 | } 95 | 96 | // Returns the managed object model for the application. 97 | // If the model doesn't already exist, it is created from the application's model. 98 | - (NSManagedObjectModel *)managedObjectModel 99 | { 100 | if (_managedObjectModel != nil) { 101 | return _managedObjectModel; 102 | } 103 | NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"DictionaryPlusPlus" withExtension:@"mom"]; 104 | _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; 105 | return _managedObjectModel; 106 | } 107 | 108 | // Returns the persistent store coordinator for the application. 109 | // If the coordinator doesn't already exist, it is created and the application's store added to it. 110 | - (NSPersistentStoreCoordinator *)persistentStoreCoordinator 111 | { 112 | if (_persistentStoreCoordinator != nil) { 113 | return _persistentStoreCoordinator; 114 | } 115 | 116 | NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"DictionaryPlusPlus.sqlite"]; 117 | 118 | NSError *error = nil; 119 | _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; 120 | if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) { 121 | /* 122 | Replace this implementation with code to handle the error appropriately. 123 | 124 | abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 125 | 126 | Typical reasons for an error here include: 127 | * The persistent store is not accessible; 128 | * The schema for the persistent store is incompatible with current managed object model. 129 | Check the error message to determine what the actual problem was. 130 | 131 | 132 | If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory. 133 | 134 | If you encounter schema incompatibility errors during development, you can reduce their frequency by: 135 | * Simply deleting the existing store: 136 | [[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil] 137 | 138 | * Performing automatic lightweight migration by passing the following dictionary as the options parameter: 139 | @{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES} 140 | 141 | Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details. 142 | 143 | */ 144 | NSLog(@"Unresolved error %@, %@", error, [error userInfo]); 145 | abort(); 146 | } 147 | 148 | return _persistentStoreCoordinator; 149 | } 150 | 151 | #pragma mark - Application's Documents directory 152 | 153 | // Returns the URL to the application's Documents directory. 154 | - (NSURL *)applicationDocumentsDirectory 155 | { 156 | return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 157 | } 158 | 159 | @end 160 | -------------------------------------------------------------------------------- /Dictionary++/Model/DictionaryPlusPlus.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Dictionary++/Model/Favorite.h: -------------------------------------------------------------------------------- 1 | // 2 | // Favorite.h 3 | // Dictionary++ 4 | // 5 | // Created by Josh Parnham on 2/04/13. 6 | // Copyright (c) 2013 Josh Parnham. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | 13 | @interface Favorite : NSManagedObject 14 | 15 | @property (nonatomic, strong) NSString * word; 16 | @property (nonatomic, strong) NSDate * dateFavorited; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Dictionary++/Model/Favorite.m: -------------------------------------------------------------------------------- 1 | // 2 | // Favorite.m 3 | // Dictionary++ 4 | // 5 | // Created by Josh Parnham on 2/04/13. 6 | // Copyright (c) 2013 Josh Parnham. All rights reserved. 7 | // 8 | 9 | #import "Favorite.h" 10 | 11 | 12 | @implementation Favorite 13 | 14 | @dynamic word; 15 | @dynamic dateFavorited; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Dictionary++/Model/Recent.h: -------------------------------------------------------------------------------- 1 | // 2 | // Recent.h 3 | // Dictionary++ 4 | // 5 | // Created by Josh Parnham on 2/04/13. 6 | // Copyright (c) 2013 Josh Parnham. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | 13 | @interface Recent : NSManagedObject 14 | 15 | @property (nonatomic, strong) NSString * word; 16 | @property (nonatomic, strong) NSDate * dateLastViewed; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Dictionary++/Model/Recent.m: -------------------------------------------------------------------------------- 1 | // 2 | // Recent.m 3 | // Dictionary++ 4 | // 5 | // Created by Josh Parnham on 2/04/13. 6 | // Copyright (c) 2013 Josh Parnham. All rights reserved. 7 | // 8 | 9 | #import "Recent.h" 10 | 11 | 12 | @implementation Recent 13 | 14 | @dynamic word; 15 | @dynamic dateLastViewed; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Dictionary++/Screenshots/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Screenshots/1.png -------------------------------------------------------------------------------- /Dictionary++/Screenshots/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Screenshots/2.png -------------------------------------------------------------------------------- /Dictionary++/Screenshots/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/josh-/DictionaryPlusPlus/a2b5157621277ec70fb5f26c02079a91151833ec/Dictionary++/Screenshots/3.png -------------------------------------------------------------------------------- /Dictionary++/View Controllers/JPMainViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JPMainViewController.h 3 | // Dictionary++ 4 | // 5 | // Created by Josh Parnham on 1/04/13. 6 | // Copyright (c) 2013 Josh Parnham. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JPMainViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Dictionary++/View Controllers/JPMainViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JPMainViewController.m 3 | // Dictionary++ 4 | // 5 | // Created by Josh Parnham on 1/04/13. 6 | // Copyright (c) 2013 Josh Parnham. All rights reserved. 7 | // 8 | 9 | #import "JPMainViewController.h" 10 | #import "JPReferenceLibraryViewController.h" 11 | #import "JPUserListViewController.h" 12 | 13 | @interface JPMainViewController () 14 | 15 | @property (strong, nonatomic) UISearchBar *searchBar; 16 | 17 | @property (strong, nonatomic) UITextChecker *textChecker; 18 | @property (strong, nonatomic) NSMutableArray *words; 19 | @property (strong, nonatomic) NSMutableArray *ignoredWords; 20 | 21 | @end 22 | 23 | @implementation JPMainViewController 24 | 25 | - (id)initWithStyle:(UITableViewStyle)style 26 | { 27 | self = [super initWithStyle:style]; 28 | if (self) { 29 | 30 | self.searchBar = [[UISearchBar alloc] init]; 31 | self.searchBar.delegate = self; 32 | self.searchBar.autocorrectionType = UITextAutocorrectionTypeNo; 33 | self.searchBar.spellCheckingType = UITextSpellCheckingTypeNo; 34 | self.navigationItem.titleView = self.searchBar; 35 | [self.searchBar sizeToFit]; 36 | 37 | UIBarButtonItem *recentsBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemBookmarks target:self action:@selector(recentButtonTapped:)]; 38 | self.navigationItem.rightBarButtonItem = recentsBarButtonItem; 39 | 40 | self.textChecker = [[UITextChecker alloc] init]; 41 | self.words = [[NSMutableArray alloc] init]; 42 | self.ignoredWords = [NSMutableArray array]; 43 | } 44 | return self; 45 | } 46 | 47 | - (void)viewDidLoad 48 | { 49 | [super viewDidLoad]; 50 | 51 | [self.searchBar becomeFirstResponder]; 52 | } 53 | 54 | - (void)viewWillAppear:(BOOL)animated 55 | { 56 | [super viewWillAppear:animated]; 57 | 58 | if (![self.searchBar isFirstResponder]) { 59 | [self.searchBar becomeFirstResponder]; 60 | } 61 | } 62 | 63 | - (void)didReceiveMemoryWarning 64 | { 65 | [super didReceiveMemoryWarning]; 66 | 67 | [self.ignoredWords removeAllObjects]; 68 | } 69 | 70 | #pragma mark - Search bar delegate 71 | 72 | - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText 73 | { 74 | [self updateWords]; 75 | 76 | [self.tableView reloadData]; 77 | } 78 | 79 | - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar 80 | { 81 | if ([UIReferenceLibraryViewController dictionaryHasDefinitionForTerm:searchBar.text]) { 82 | [searchBar resignFirstResponder]; 83 | 84 | JPReferenceLibraryViewController *referenceLibraryViewController = [[JPReferenceLibraryViewController alloc] initWithTerm:searchBar.text]; 85 | [self.navigationController pushViewController:referenceLibraryViewController animated:YES]; 86 | } 87 | } 88 | 89 | #pragma mark - Table view data source 90 | 91 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 92 | { 93 | return [self.words count]; 94 | } 95 | 96 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 97 | { 98 | NSString *CellIdentifier = @"CellIdentifier"; 99 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 100 | if (cell == nil) { 101 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 102 | } 103 | 104 | cell.textLabel.text = [self.words objectAtIndex:indexPath.row]; 105 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 106 | 107 | return cell; 108 | } 109 | 110 | #pragma mark - Table view delegate 111 | 112 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 113 | { 114 | [self.searchBar resignFirstResponder]; 115 | 116 | NSString *word = [self.words objectAtIndex:indexPath.row]; 117 | JPReferenceLibraryViewController *referenceLibraryViewController = [[JPReferenceLibraryViewController alloc] initWithTerm:word]; 118 | [self.navigationController pushViewController:referenceLibraryViewController animated:YES]; 119 | 120 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 121 | } 122 | 123 | #pragma mark - Text checker 124 | 125 | - (void)updateWords 126 | { 127 | [self.words removeAllObjects]; 128 | 129 | NSString *word = self.searchBar.text; 130 | NSRange range = NSMakeRange(0, word.length); 131 | 132 | for (NSString *language in [NSLocale preferredLanguages]) { 133 | NSArray *guesses = [self.textChecker guessesForWordRange:range inString:word language:language]; 134 | 135 | for (int i = 0; i < [guesses count]; i++) { 136 | if ([self.ignoredWords count] > 0) { 137 | if (![self.ignoredWords containsObject:guesses[i]]) { 138 | [self.words addObject:guesses[i]]; 139 | } 140 | } 141 | else { 142 | [self.words addObject:guesses[i]]; 143 | } 144 | } 145 | 146 | NSArray *completions = [self.textChecker completionsForPartialWordRange:range inString:word language:language]; 147 | 148 | for (int i = 0; i < [completions count]; i++) { 149 | if ([self.ignoredWords count] > 0) { 150 | if (![self.ignoredWords containsObject:completions[i]]) { 151 | [self.words addObject:completions[i]]; 152 | } 153 | } 154 | else { 155 | [self.words addObject:completions[i]]; 156 | } 157 | } 158 | } 159 | 160 | dispatch_async( dispatch_get_global_queue(0, 0), ^{ 161 | [self trimWords]; 162 | }); 163 | } 164 | 165 | - (void)trimWords 166 | { 167 | /* 168 | UIReferenceLibraryViewController's +dictionaryHasDefinitionForTerm: method can be quite time-consuming (taking up to 0.3 seconds in my testing) and thus should only be done in a background thread when being called on multiple NSStrings 169 | */ 170 | 171 | NSMutableArray *trimmedArray = [[NSMutableArray alloc] initWithArray:self.words]; 172 | for (int i = 0; i<[trimmedArray count]; i++) { 173 | if (![UIReferenceLibraryViewController dictionaryHasDefinitionForTerm:[trimmedArray objectAtIndex:i]]) { 174 | [self.ignoredWords addObject:[trimmedArray objectAtIndex:i]]; 175 | } 176 | } 177 | } 178 | 179 | #pragma mark - Methods 180 | 181 | - (void)recentButtonTapped:(id)sender 182 | { 183 | JPUserListViewController *userListViewController = [[JPUserListViewController alloc] init]; 184 | UINavigationController *userListNavigationController = [[UINavigationController alloc] initWithRootViewController:userListViewController]; 185 | [self presentViewController:userListNavigationController animated:YES completion:nil]; 186 | } 187 | 188 | @end 189 | -------------------------------------------------------------------------------- /Dictionary++/View Controllers/JPReferenceLibraryViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JPReferenceLibraryViewController.h 3 | // Dictionary++ 4 | // 5 | // Created by Josh Parnham on 1/04/13. 6 | // Copyright (c) 2013 Josh Parnham. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JPReferenceLibraryViewController : UIReferenceLibraryViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Dictionary++/View Controllers/JPReferenceLibraryViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JPReferenceLibraryViewController.m 3 | // Dictionary++ 4 | // 5 | // Created by Josh Parnham on 1/04/13. 6 | // Copyright (c) 2013 Josh Parnham. All rights reserved. 7 | // 8 | 9 | #import "JPReferenceLibraryViewController.h" 10 | #import "JPAppDelegate.h" 11 | #import "Recent.h" 12 | #import "Favorite.h" 13 | 14 | @interface JPReferenceLibraryViewController () 15 | 16 | @property (copy) NSString *term; 17 | 18 | @property (strong, nonatomic) NSManagedObjectContext *managedObjectContext; 19 | 20 | @end 21 | 22 | @implementation JPReferenceLibraryViewController 23 | 24 | - (id)initWithTerm:(NSString *)term 25 | { 26 | self = [super initWithTerm:term]; 27 | if (self) { 28 | self.term = term; 29 | 30 | self.managedObjectContext = [(JPAppDelegate *)[UIApplication sharedApplication].delegate managedObjectContext]; 31 | 32 | [self addRecentItem]; 33 | } 34 | return self; 35 | } 36 | 37 | - (void)viewDidLoad 38 | { 39 | [super viewDidLoad]; 40 | [self setUpBarButtonItems]; 41 | } 42 | 43 | #pragma mark - Methods 44 | 45 | - (void)addRecentItem 46 | { 47 | NSFetchRequest *request = [[NSFetchRequest alloc] init]; 48 | request.entity = [NSEntityDescription entityForName:@"Recent" inManagedObjectContext:self.managedObjectContext]; 49 | NSPredicate *predicate = [NSPredicate predicateWithFormat:@"word == %@", self.term]; 50 | request.predicate = predicate; 51 | NSArray *wordArray = [self.managedObjectContext executeFetchRequest:request error:nil]; 52 | 53 | if (wordArray.count == 0) { // Word isn't already in the Recent list 54 | Recent *recent = [[Recent alloc] initWithEntity:[NSEntityDescription entityForName:@"Recent" inManagedObjectContext:self.managedObjectContext] insertIntoManagedObjectContext:self.managedObjectContext]; 55 | recent.word = self.term; 56 | recent.dateLastViewed = [NSDate date]; 57 | [self.managedObjectContext save:nil]; 58 | 59 | return; 60 | } 61 | else { // Word is already in the Recent list 62 | for (Recent *recent in wordArray) { 63 | recent.dateLastViewed = [NSDate date]; 64 | [self.managedObjectContext save:nil]; 65 | } 66 | } 67 | } 68 | 69 | - (void)setUpBarButtonItems 70 | { 71 | NSFetchRequest *request = [[NSFetchRequest alloc] init]; 72 | request.entity = [NSEntityDescription entityForName:@"Favorite" inManagedObjectContext:self.managedObjectContext]; 73 | NSPredicate *predicate = [NSPredicate predicateWithFormat:@"word == %@", self.term]; 74 | request.predicate = predicate; 75 | NSArray *wordArray = [self.managedObjectContext executeFetchRequest:request error:nil]; 76 | 77 | NSString *buttonText; 78 | SEL buttonSelector; 79 | 80 | if ([wordArray count] == 0) { // Word hasn't been favorited 81 | buttonText = NSLocalizedString(@"Favorite", @"Bar button item for an item that has not been marked as a favorite"); 82 | buttonSelector = @selector(favoriteWord:); 83 | } 84 | else { // Word has already been favorited 85 | buttonText = NSLocalizedString(@"Unfavorite", @"Bar button item for an item that has been marked as a favorite"); 86 | buttonSelector = @selector(unfavoriteWord:); 87 | } 88 | 89 | UIBarButtonItem *favoriteBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:buttonText style:UIBarButtonItemStylePlain target:self action:buttonSelector]; 90 | favoriteBarButtonItem.possibleTitles = [NSSet setWithObjects:@"Favorite", @"Unfavorite", nil]; 91 | self.navigationItem.rightBarButtonItem = favoriteBarButtonItem; 92 | } 93 | 94 | - (void)favoriteWord:(id)sender 95 | { 96 | Favorite *favorite = [[Favorite alloc] initWithEntity:[NSEntityDescription entityForName:@"Favorite" inManagedObjectContext:self.managedObjectContext] insertIntoManagedObjectContext:self.managedObjectContext]; 97 | favorite.word = self.term; 98 | favorite.dateFavorited = [NSDate date]; 99 | [self.managedObjectContext save:nil]; 100 | 101 | [self setUpBarButtonItems]; 102 | } 103 | 104 | - (void)unfavoriteWord:(id)sender 105 | { 106 | NSFetchRequest *request = [[NSFetchRequest alloc] init]; 107 | request.entity = [NSEntityDescription entityForName:@"Favorite" inManagedObjectContext:self.managedObjectContext]; 108 | NSPredicate *predicate = [NSPredicate predicateWithFormat:@"word == %@", self.term]; 109 | request.predicate = predicate; 110 | NSArray *wordArray = [self.managedObjectContext executeFetchRequest:request error:nil]; 111 | 112 | for (Favorite *favorite in wordArray) { 113 | [self.managedObjectContext deleteObject:favorite]; 114 | } 115 | [self.managedObjectContext save:nil]; 116 | 117 | [self setUpBarButtonItems]; 118 | } 119 | 120 | @end 121 | -------------------------------------------------------------------------------- /Dictionary++/View Controllers/JPUserListViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JPUserListViewController.h 3 | // Dictionary++ 4 | // 5 | // Created by Josh Parnham on 1/04/13. 6 | // Copyright (c) 2013 Josh Parnham. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JPUserListViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Dictionary++/View Controllers/JPUserListViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JPUserListViewController.m 3 | // Dictionary++ 4 | // 5 | // Created by Josh Parnham on 1/04/13. 6 | // Copyright (c) 2013 Josh Parnham. All rights reserved. 7 | // 8 | 9 | #import "JPUserListViewController.h" 10 | #import "JPReferenceLibraryViewController.h" 11 | #import "JPAppDelegate.h" 12 | #import "Recent.h" 13 | #import "Favorite.h" 14 | 15 | @interface JPUserListViewController () 16 | 17 | @property (strong, nonatomic) UISegmentedControl *segmentedControl; 18 | @property (strong, nonatomic) NSMutableArray *wordsArray; 19 | 20 | @end 21 | 22 | @implementation JPUserListViewController 23 | 24 | - (id)initWithStyle:(UITableViewStyle)style 25 | { 26 | self = [super initWithStyle:UITableViewStylePlain]; 27 | if (self) { 28 | NSArray *segmentTitles = @[NSLocalizedString(@"Recent", @"Recent items segment control title"), NSLocalizedString(@"Favorites", @"Favorite items segment control title")]; 29 | self.segmentedControl = [[UISegmentedControl alloc] initWithItems:segmentTitles]; 30 | [self.segmentedControl addTarget:self action:@selector(segmentedControlIndexChanged:) forControlEvents:UIControlEventValueChanged]; 31 | [self.segmentedControl setSelectedSegmentIndex:0]; 32 | self.navigationItem.titleView = self.segmentedControl; 33 | [self.segmentedControl sizeToFit]; 34 | 35 | self.wordsArray = [[NSMutableArray alloc] init]; 36 | 37 | UIBarButtonItem *doneBarButttonItem = [[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Done", @"Done bar button title") style:UIBarButtonItemStyleDone target:self action:@selector(doneTapped:)]; 38 | self.navigationItem.rightBarButtonItem = doneBarButttonItem; 39 | 40 | } 41 | return self; 42 | } 43 | 44 | - (void)viewDidLoad 45 | { 46 | [super viewDidLoad]; 47 | [self updateWordsArray]; 48 | } 49 | 50 | #pragma mark - Methods 51 | 52 | - (void)updateWordsArray 53 | { 54 | [self.wordsArray removeAllObjects]; 55 | NSFetchRequest *request = [[NSFetchRequest alloc] init]; 56 | NSManagedObjectContext *managedObjectContext = [(JPAppDelegate *)[UIApplication sharedApplication].delegate managedObjectContext]; 57 | NSSortDescriptor *sortDescriptor; 58 | 59 | switch (self.segmentedControl.selectedSegmentIndex) { 60 | case 0: 61 | request.entity = [NSEntityDescription entityForName:@"Recent" inManagedObjectContext:managedObjectContext]; 62 | sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"dateLastAccessed" ascending:YES selector:@selector(compare:)]; 63 | [self.wordsArray addObjectsFromArray:[managedObjectContext executeFetchRequest:request error:nil]]; 64 | break; 65 | case 1: 66 | request.entity = [NSEntityDescription entityForName:@"Favorite" inManagedObjectContext:managedObjectContext]; 67 | sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"dateFavorited" ascending:YES selector:@selector(compare:)]; 68 | [self.wordsArray addObjectsFromArray:[managedObjectContext executeFetchRequest:request error:nil]]; 69 | break; 70 | 71 | default: 72 | break; 73 | } 74 | } 75 | 76 | - (void)doneTapped:(id)sender 77 | { 78 | [self dismissViewControllerAnimated:YES completion:nil]; 79 | } 80 | 81 | - (void)segmentedControlIndexChanged:(id)sender 82 | { 83 | [self updateWordsArray]; 84 | [self.tableView reloadData]; 85 | } 86 | 87 | #pragma mark - Table view data source 88 | 89 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 90 | { 91 | return [self.wordsArray count]; 92 | } 93 | 94 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 95 | { 96 | NSString *CellIdentifier = @"CellIdentifier"; 97 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 98 | if (cell == nil) { 99 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; 100 | } 101 | 102 | cell.textLabel.text = [[self.wordsArray objectAtIndex:indexPath.row] word]; 103 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 104 | 105 | return cell; 106 | } 107 | 108 | #pragma mark - Table view delegate 109 | 110 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 111 | { 112 | NSString *word = [(Recent *)[self.wordsArray objectAtIndex:indexPath.row] word]; 113 | JPReferenceLibraryViewController *referenceLibraryViewController = [[JPReferenceLibraryViewController alloc] initWithTerm:word]; 114 | [self.navigationController pushViewController:referenceLibraryViewController animated:YES]; 115 | } 116 | 117 | @end 118 | -------------------------------------------------------------------------------- /Dictionary++/en-AU.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Dictionary++/en-AU.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | Dictionary++ 4 | 5 | Created by Josh Parnham on 7/4/18. 6 | Copyright © 2018 Josh Parnham. All rights reserved. 7 | */ 8 | 9 | "Favorite" = "Favourite"; 10 | "Unfavorite" = "Unfavourite"; 11 | "Recent" = "Recent"; 12 | "Favorites" = "Favourites"; 13 | "Done" = "Done"; 14 | -------------------------------------------------------------------------------- /Dictionary++/en-GB.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Dictionary++/en-GB.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* 2 | Localizable.strings 3 | Dictionary++ 4 | 5 | Created by Josh Parnham on 7/4/18. 6 | Copyright © 2018 Josh Parnham. All rights reserved. 7 | */ 8 | 9 | "Favorite" = "Favourite"; 10 | "Unfavorite" = "Unfavourite"; 11 | "Recent" = "Recent"; 12 | "Favorites" = "Favourites"; 13 | "Done" = "Done"; 14 | -------------------------------------------------------------------------------- /Dictionary++/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Dictionary++/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Dictionary++ 4 | // 5 | // Created by Josh Parnham on 1/04/13. 6 | // Copyright (c) 2013 Josh Parnham. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "JPAppDelegate.h" 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([JPAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright 2017 Josh Parnham 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Dictionary++ 2 | 3 | Inspired by [Dictionary+](http://iphone.qualityindex.com/apps/571492/dictionary) (pulled from the store for violating the [`UIReferenceLibraryViewController` terms of use](https://developer.apple.com/documentation/uikit/uireferencelibraryviewcontroller)), Dictionary++ is a simple interface to iOS's system dictionary. 4 | 5 | Since this app also violates the aforementioned rules, it can't be submitted to the App Store and thus you need to compile, sign and install it on your devices yourself if you want to use it. 6 | 7 | Licensed under the [MIT](http://opensource.org/licenses/MIT). 8 | 9 | ## Screenshots 10 | 11 | Searching for words Viewing a word's definition Viewing the user's favorite words 12 | --------------------------------------------------------------------------------