diff --git a/SQManagement/SQManagement.xcodeproj/project.pbxproj b/SQManagement/SQManagement.xcodeproj/project.pbxproj index 871585c0..21c23391 100644 --- a/SQManagement/SQManagement.xcodeproj/project.pbxproj +++ b/SQManagement/SQManagement.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 14D633B0233763FF004FD86A /* SQAuthorizationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 14D633AF233763FF004FD86A /* SQAuthorizationManager.m */; }; + 14D633B52337674F004FD86A /* SQSearchInputView.m in Sources */ = {isa = PBXBuildFile; fileRef = 14D633B22337674F004FD86A /* SQSearchInputView.m */; }; + 14D633B62337674F004FD86A /* SQSearchInputView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 14D633B42337674F004FD86A /* SQSearchInputView.xib */; }; 14DC37CB23374CFB00867A92 /* SQH1TitleView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 14DC37C923374CFB00867A92 /* SQH1TitleView.xib */; }; 14DC37CC23374CFB00867A92 /* SQH1TitleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 14DC37CA23374CFB00867A92 /* SQH1TitleView.m */; }; 14DC37CF23374DC600867A92 /* SQConnectionsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 14DC37CE23374DC600867A92 /* SQConnectionsViewController.m */; }; @@ -27,6 +30,11 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 14D633AE233763FF004FD86A /* SQAuthorizationManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SQAuthorizationManager.h; sourceTree = ""; }; + 14D633AF233763FF004FD86A /* SQAuthorizationManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SQAuthorizationManager.m; sourceTree = ""; }; + 14D633B22337674F004FD86A /* SQSearchInputView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQSearchInputView.m; sourceTree = ""; }; + 14D633B32337674F004FD86A /* SQSearchInputView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQSearchInputView.h; sourceTree = ""; }; + 14D633B42337674F004FD86A /* SQSearchInputView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SQSearchInputView.xib; sourceTree = ""; }; 14DC37C823374CFB00867A92 /* SQH1TitleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SQH1TitleView.h; sourceTree = ""; }; 14DC37C923374CFB00867A92 /* SQH1TitleView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SQH1TitleView.xib; sourceTree = ""; }; 14DC37CA23374CFB00867A92 /* SQH1TitleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SQH1TitleView.m; sourceTree = ""; }; @@ -72,9 +80,21 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 14D633B123376549004FD86A /* Tools */ = { + isa = PBXGroup; + children = ( + 14D633AE233763FF004FD86A /* SQAuthorizationManager.h */, + 14D633AF233763FF004FD86A /* SQAuthorizationManager.m */, + ); + path = Tools; + sourceTree = ""; + }; 14DC37D023374F6E00867A92 /* Coms */ = { isa = PBXGroup; children = ( + 14D633B32337674F004FD86A /* SQSearchInputView.h */, + 14D633B22337674F004FD86A /* SQSearchInputView.m */, + 14D633B42337674F004FD86A /* SQSearchInputView.xib */, 14DC37C823374CFB00867A92 /* SQH1TitleView.h */, 14DC37CA23374CFB00867A92 /* SQH1TitleView.m */, 14DC37C923374CFB00867A92 /* SQH1TitleView.xib */, @@ -144,6 +164,7 @@ children = ( 14DC37D123374F7700867A92 /* Main */, 14DC37D023374F6E00867A92 /* Coms */, + 14D633B123376549004FD86A /* Tools */, 14DC37E423374FC300867A92 /* UI */, 14DC37D423374FA500867A92 /* SQExtension */, 14E97DCE2335014B004FC20D /* Main.storyboard */, @@ -231,6 +252,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 14D633B62337674F004FD86A /* SQSearchInputView.xib in Resources */, 14DC37CB23374CFB00867A92 /* SQH1TitleView.xib in Resources */, 14E97DD82335014C004FC20D /* LaunchScreen.storyboard in Resources */, 14E97DD52335014C004FC20D /* Assets.xcassets in Resources */, @@ -278,8 +300,10 @@ 14E97DC72335014B004FC20D /* AppDelegate.m in Sources */, 14E97DD32335014B004FC20D /* SQManagement.xcdatamodeld in Sources */, 14DC37CC23374CFB00867A92 /* SQH1TitleView.m in Sources */, + 14D633B0233763FF004FD86A /* SQAuthorizationManager.m in Sources */, 14DC37E023374FA500867A92 /* NSObject+SQExtension.m in Sources */, 14DC37CF23374DC600867A92 /* SQConnectionsViewController.m in Sources */, + 14D633B52337674F004FD86A /* SQSearchInputView.m in Sources */, 14E97DCA2335014B004FC20D /* SceneDelegate.m in Sources */, 14DC37E223374FA500867A92 /* UIImage+SQExtension.m in Sources */, ); @@ -425,6 +449,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = BMZP26248F; INFOPLIST_FILE = SQManagement/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -443,6 +468,7 @@ CODE_SIGN_STYLE = Automatic; DEVELOPMENT_TEAM = BMZP26248F; INFOPLIST_FILE = SQManagement/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/SQManagement/SQManagement/Assets.xcassets/search_icon.imageset/Contents.json b/SQManagement/SQManagement/Assets.xcassets/search_icon.imageset/Contents.json new file mode 100644 index 00000000..dcfd3cb7 --- /dev/null +++ b/SQManagement/SQManagement/Assets.xcassets/search_icon.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "search_icon-2.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/SQManagement/SQManagement/Assets.xcassets/search_icon.imageset/search_icon-2.png b/SQManagement/SQManagement/Assets.xcassets/search_icon.imageset/search_icon-2.png new file mode 100644 index 00000000..3146e336 Binary files /dev/null and b/SQManagement/SQManagement/Assets.xcassets/search_icon.imageset/search_icon-2.png differ diff --git a/SQManagement/SQManagement/Coms/SQSearchInputView.h b/SQManagement/SQManagement/Coms/SQSearchInputView.h new file mode 100644 index 00000000..7942d64d --- /dev/null +++ b/SQManagement/SQManagement/Coms/SQSearchInputView.h @@ -0,0 +1,21 @@ +// +// SQSearchInputView.h +// SQMagnet +// +// Created by 朱双泉 on 2019/7/12. +// Copyright © 2019 Castie!. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface SQSearchInputView : UIView + ++ (instancetype)inputView; + +- (void)hookApplicationWillEnterForeground; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SQManagement/SQManagement/Coms/SQSearchInputView.m b/SQManagement/SQManagement/Coms/SQSearchInputView.m new file mode 100644 index 00000000..75d5a28e --- /dev/null +++ b/SQManagement/SQManagement/Coms/SQSearchInputView.m @@ -0,0 +1,60 @@ +// +// SQSearchInputView.m +// SQMagnet +// +// Created by 朱双泉 on 2019/7/12. +// Copyright © 2019 Castie!. All rights reserved. +// + +#import "SQSearchInputView.h" +#import "UIColor+SQExtension.h" +#import "NSObject+SQExtension.h" +#import "UIView+SQExtension.h" + +@interface SQSearchInputView () + +@property (weak, nonatomic) IBOutlet UITextField *textField; +@property (nonatomic, strong) NSMutableDictionary *dict; + +@end + +@implementation SQSearchInputView + ++ (instancetype)inputView { + SQSearchInputView *inputView = [[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self.class) owner:nil options:nil].firstObject; + [inputView hookApplicationWillEnterForeground]; + return inputView; +} + +- (void)awakeFromNib { + [super awakeFromNib]; + self.textField.delegate = self; + UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"search_icon"]]; + UIView *leftView = [UIView new]; + leftView.frame = CGRectMake(5, 0, imageView.width + 10, self.textField.height); + imageView.center = leftView.center; + [leftView addSubview:imageView]; + self.textField.leftView = leftView; + self.textField.leftViewMode = UITextFieldViewModeAlways; +} + +- (void)hookApplicationWillEnterForeground { + if (@available(iOS 13.0, *)) { + self.textField.backgroundColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull trait) { + if (trait.userInterfaceStyle == UIUserInterfaceStyleDark) { + return [[UIColor colorWithHexString:@"#1c1c1e"] colorWithAlphaComponent:0.7f]; + } else { + return [[UIColor colorWithHexString:@"#eeeeef"] colorWithAlphaComponent:0.7f]; + } + }]; + self.textField.textColor = [UIColor colorWithDynamicProvider:^UIColor * _Nonnull(UITraitCollection * _Nonnull trait) { + if (trait.userInterfaceStyle == UIUserInterfaceStyleDark) { + return [UIColor whiteColor]; + } else { + return [UIColor blackColor]; + } + }]; + } +} + +@end diff --git a/SQManagement/SQManagement/Coms/SQSearchInputView.xib b/SQManagement/SQManagement/Coms/SQSearchInputView.xib new file mode 100644 index 00000000..25b32cd4 --- /dev/null +++ b/SQManagement/SQManagement/Coms/SQSearchInputView.xib @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SQManagement/SQManagement/Tools/SQAuthorizationManager.h b/SQManagement/SQManagement/Tools/SQAuthorizationManager.h new file mode 100644 index 00000000..11d7240b --- /dev/null +++ b/SQManagement/SQManagement/Tools/SQAuthorizationManager.h @@ -0,0 +1,19 @@ +// +// SQAuthorizationManager.h +// SQManagement +// +// Created by 朱双泉 on 2019/9/22. +// Copyright © 2019 Castie!. All rights reserved. +// + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface SQAuthorizationManager : NSObject + ++ (void)fetchContacts: (void(^)(NSString *, NSArray *))callback; + +@end + +NS_ASSUME_NONNULL_END diff --git a/SQManagement/SQManagement/Tools/SQAuthorizationManager.m b/SQManagement/SQManagement/Tools/SQAuthorizationManager.m new file mode 100644 index 00000000..ae3b5ca7 --- /dev/null +++ b/SQManagement/SQManagement/Tools/SQAuthorizationManager.m @@ -0,0 +1,42 @@ +// +// SQAuthorizationManager.m +// SQManagement +// +// Created by 朱双泉 on 2019/9/22. +// Copyright © 2019 Castie!. All rights reserved. +// + +#import "SQAuthorizationManager.h" +#import + +@implementation SQAuthorizationManager + ++ (void)fetchContacts:(void (^)(NSString *, NSArray *))callback { + dispatch_async(dispatch_get_main_queue(), ^{ + CNContactStore *store = [[CNContactStore alloc] init]; + CNAuthorizationStatus status = [CNContactStore authorizationStatusForEntityType: CNEntityTypeContacts]; + if (status == CNAuthorizationStatusNotDetermined) { + [store requestAccessForEntityType:CNEntityTypeContacts completionHandler:^(BOOL granted, NSError * _Nullable error) { + if (granted) { + NSLog(@"联系人授权成功"); + } else { + NSLog(@"联系人授权失败"); + } + }]; + } + CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[CNContactFamilyNameKey, CNContactGivenNameKey,CNContactPhoneNumbersKey]]; + [store enumerateContactsWithFetchRequest:request error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) { + NSString *name = [contact.familyName stringByAppendingString:contact.givenName]; + NSMutableArray *phoneNumbers = @[].mutableCopy; + for (CNLabeledValue *phoneNumber in contact.phoneNumbers) { + CNPhoneNumber *phoneNumberValue = phoneNumber.value; + [phoneNumbers addObject:phoneNumberValue.stringValue]; + } + if (callback) { + callback(name, phoneNumbers); + } + }]; + }); +} + +@end diff --git a/SQManagement/SQManagement/UI/SQConnectionsViewController.m b/SQManagement/SQManagement/UI/SQConnectionsViewController.m index 2ac231fd..eee8306d 100644 --- a/SQManagement/SQManagement/UI/SQConnectionsViewController.m +++ b/SQManagement/SQManagement/UI/SQConnectionsViewController.m @@ -9,12 +9,13 @@ #import "SQConnectionsViewController.h" #import "UIViewController+SQExtension.h" #import "SQH1TitleView.h" -#import +#import "SQSearchInputView.h" +#import "SQAuthorizationManager.h" @interface SQConnectionsViewController () @property (nonatomic, weak) UILabel *titleLabel; @property (nonatomic, weak) UIColor *defaultColor; - +@property (nonatomic, strong) NSMutableArray *dataSource; @end @implementation SQConnectionsViewController @@ -31,15 +32,40 @@ - (void)viewDidLoad { titleLabel.frame = self.titleLabel.frame; self.navigationItem.titleView = titleLabel; self.titleLabel = titleLabel; + + self.dataSource = @[].mutableCopy; + [SQAuthorizationManager fetchContacts:^(NSString *name, NSArray *phoneNumbers) { + [self.dataSource addObject:name]; + [self.tableView reloadData]; + }]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { - return 1; + return 2; +} + +- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + if (section == 0) return 0; + else return self.dataSource.count; +} + +- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { + UITableViewCell *cell= [tableView dequeueReusableCellWithIdentifier:@"cell"]; + if (!cell) { + cell = [[UITableViewCell alloc] initWithStyle:(UITableViewCellStyleDefault) reuseIdentifier:@"cell"]; + } + cell.textLabel.text = self.dataSource[indexPath.row]; + return cell; } - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { if (section == 0) return [SQH1TitleView viewWithTitle:self.title]; - else return nil; + else return [SQSearchInputView inputView]; +} + +- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { + if (section == 0) return 64; + return 44; } - (void)scrollViewDidScroll:(UIScrollView *)scrollView {