diff --git a/SUPLA.xcodeproj/project.pbxproj b/SUPLA.xcodeproj/project.pbxproj index f2f86c6d..4a8cf6c6 100644 --- a/SUPLA.xcodeproj/project.pbxproj +++ b/SUPLA.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 012023C2234E54ED00E131B7 /* ImpulseCounterDetailView.m in Sources */ = {isa = PBXBuildFile; fileRef = 012023C1234E54ED00E131B7 /* ImpulseCounterDetailView.m */; }; + 012119152368C3B2004C1993 /* collapsed@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 012119142368C3B2004C1993 /* collapsed@3x.png */; }; 0122613922F396440013E6A2 /* SAThermostatCalendar.m in Sources */ = {isa = PBXBuildFile; fileRef = 0122613822F396440013E6A2 /* SAThermostatCalendar.m */; }; 012F722C22DF3E2300E5F72E /* ChartFilterFieldTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 012F722822DF3CF000E5F72E /* ChartFilterFieldTests.m */; }; 012F722E22DFA0BE00E5F72E /* SABarChartDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 012F722D22DFA0BE00E5F72E /* SABarChartDataSet.swift */; }; @@ -88,6 +89,8 @@ 01EE9BB022BA4B050029A142 /* SAChannelExtendedValue+CoreDataProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 01EE9BAF22BA4B050029A142 /* SAChannelExtendedValue+CoreDataProperties.m */; }; 01EE9BBB22BA50D90029A142 /* SAChannelValueBase+CoreDataClass.m in Sources */ = {isa = PBXBuildFile; fileRef = 01EE9BB722BA50D90029A142 /* SAChannelValueBase+CoreDataClass.m */; }; 01EE9BBC22BA50D90029A142 /* SAChannelValueBase+CoreDataProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 01EE9BB822BA50D90029A142 /* SAChannelValueBase+CoreDataProperties.m */; }; + 01EFD94A236CA94400893489 /* NSData+AES.m in Sources */ = {isa = PBXBuildFile; fileRef = 01EFD949236CA94400893489 /* NSData+AES.m */; }; + 01EFD94C236CA9AE00893489 /* NSDataEncryptionTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 01EFD94B236CA9AE00893489 /* NSDataEncryptionTest.m */; }; 01F8856922E5E79100D18373 /* SATempHumidityMeasurementItem+CoreDataClass.m in Sources */ = {isa = PBXBuildFile; fileRef = 01F8855C22E5E79000D18373 /* SATempHumidityMeasurementItem+CoreDataClass.m */; }; 01F8856A22E5E79100D18373 /* SATempHumidityMeasurementItem+CoreDataProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 01F8856322E5E79100D18373 /* SATempHumidityMeasurementItem+CoreDataProperties.m */; }; 01F8856B22E5E79100D18373 /* SAThermostatMeasurementItem+CoreDataProperties.m in Sources */ = {isa = PBXBuildFile; fileRef = 01F8855522E5E79000D18373 /* SAThermostatMeasurementItem+CoreDataProperties.m */; }; @@ -363,6 +366,8 @@ /* Begin PBXFileReference section */ 012023C0234E54ED00E131B7 /* ImpulseCounterDetailView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImpulseCounterDetailView.h; sourceTree = ""; }; 012023C1234E54ED00E131B7 /* ImpulseCounterDetailView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ImpulseCounterDetailView.m; sourceTree = ""; }; + 012119132368BDB0004C1993 /* SUPLA 5.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "SUPLA 5.xcdatamodel"; sourceTree = ""; }; + 012119142368C3B2004C1993 /* collapsed@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "collapsed@3x.png"; path = "Resources/Assets/Img/collapsed@3x.png"; sourceTree = ""; }; 0122613722F396440013E6A2 /* SAThermostatCalendar.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SAThermostatCalendar.h; sourceTree = ""; }; 0122613822F396440013E6A2 /* SAThermostatCalendar.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SAThermostatCalendar.m; sourceTree = ""; }; 012F722822DF3CF000E5F72E /* ChartFilterFieldTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ChartFilterFieldTests.m; sourceTree = ""; }; @@ -588,6 +593,9 @@ 01EE9BB622BA50D90029A142 /* SAChannelValueBase+CoreDataClass.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SAChannelValueBase+CoreDataClass.h"; sourceTree = ""; }; 01EE9BB722BA50D90029A142 /* SAChannelValueBase+CoreDataClass.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SAChannelValueBase+CoreDataClass.m"; sourceTree = ""; }; 01EE9BB822BA50D90029A142 /* SAChannelValueBase+CoreDataProperties.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SAChannelValueBase+CoreDataProperties.m"; sourceTree = ""; }; + 01EFD948236CA94400893489 /* NSData+AES.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSData+AES.h"; sourceTree = ""; }; + 01EFD949236CA94400893489 /* NSData+AES.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSData+AES.m"; sourceTree = ""; }; + 01EFD94B236CA9AE00893489 /* NSDataEncryptionTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NSDataEncryptionTest.m; sourceTree = ""; }; 01F8855522E5E79000D18373 /* SAThermostatMeasurementItem+CoreDataProperties.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SAThermostatMeasurementItem+CoreDataProperties.m"; sourceTree = ""; }; 01F8855622E5E79000D18373 /* SAImpulseCounterMeasurementItem+CoreDataClass.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "SAImpulseCounterMeasurementItem+CoreDataClass.m"; sourceTree = ""; }; 01F8855722E5E79000D18373 /* SAImpulseCounterMeasurementItem+CoreDataProperties.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SAImpulseCounterMeasurementItem+CoreDataProperties.h"; sourceTree = ""; }; @@ -995,6 +1003,36 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 012119122368B597004C1993 /* xib */ = { + isa = PBXGroup; + children = ( + 01C8EBCF23422AC50072AB8C /* HomePlusDetailViewGroupCell.xib */, + 40CE7C6D1DCBBF6D00BBACE4 /* DistanceCell.xib */, + 017A3C8823633A70004AD1FC /* TempHumidityDetailView.xib */, + 01902A29235A1840005ED935 /* TemperatureDetailView.xib */, + 407D4AFE1BC6E491009A5505 /* StatusVC.xib */, + 40BE3E611BCA7AEF00153680 /* ChannelCell.xib */, + 406778541BCBF9F4008DD37F /* SectionCell.xib */, + 40DE1A3A1BCD5E9B004CF43B /* AboutVC.xib */, + 4038A5531CE32B6800180B5D /* TempHumidityCell.xib */, + 40DB208F1DC9049400FAFAB0 /* RGBDetail.xib */, + 019F4CAE2354DC3300286139 /* ImpulseCounterDetailView.xib */, + 01D0617322C296850043C947 /* ElectricityMeterDetailView.xib */, + 01C8EBFC234232EC0072AB8C /* HomePlusDetailView.xib */, + 40CE7C631DCBBCE400BBACE4 /* MeasurementCell.xib */, + 40F951471FD0654900698587 /* RSDetail.xib */, + 407D31961FD1A7070062FB80 /* AddWizardVC.xib */, + 4077ACE220A21BB100BD2216 /* CreateAccountVC.xib */, + 01F9111022EF989100BFF91D /* HomePlusCell.xib */, + 40844D811FB0DDB000432AA0 /* SettingsVC.xib */, + 401CA1EE1BA0923600117AF4 /* MainVC.xib */, + 408034E41BC84A89007666E7 /* NavigationController.xib */, + 01D4293922AAAA450050C1A2 /* IncrementalMeterCell.xib */, + 406778281BCBBC83008DD37F /* ThermometerCell.xib */, + ); + name = xib; + sourceTree = ""; + }; 013D1C5A22CE4751000C0784 /* charts */ = { isa = PBXGroup; children = ( @@ -1107,6 +1145,8 @@ 40A675851BA1BEBF004A51C4 /* UI */, 40A6757D1BA1A5B6004A51C4 /* SuplaApp.h */, 40A6757E1BA1A5B6004A51C4 /* SuplaApp.m */, + 01EFD948236CA94400893489 /* NSData+AES.h */, + 01EFD949236CA94400893489 /* NSData+AES.m */, 401CA1C01BA067DB00117AF4 /* AppDelegate.h */, 401CA1C11BA067DB00117AF4 /* AppDelegate.m */, 401CA1CC1BA067DB00117AF4 /* Images.xcassets */, @@ -1135,6 +1175,7 @@ 401CA1D81BA067DB00117AF4 /* SUPLATests */ = { isa = PBXGroup; children = ( + 01EFD94B236CA9AE00893489 /* NSDataEncryptionTest.m */, 012F722822DF3CF000E5F72E /* ChartFilterFieldTests.m */, 401CA1DB1BA067DB00117AF4 /* SUPLATests.m */, 401CA1D91BA067DB00117AF4 /* Supporting Files */, @@ -1184,6 +1225,7 @@ 405AC4011BC15878004F7311 /* Img */ = { isa = PBXGroup; children = ( + 012119142368C3B2004C1993 /* collapsed@3x.png */, 017A3CA523635C22004AD1FC /* weight@2x.png */, 017A3CA623635C22004AD1FC /* weight@3x.png */, 017A3CAD23635DF7004AD1FC /* pressure@2x.png */, @@ -1497,7 +1539,7 @@ 40A675851BA1BEBF004A51C4 /* UI */ = { isa = PBXGroup; children = ( - 40844D811FB0DDB000432AA0 /* SettingsVC.xib */, + 012119122368B597004C1993 /* xib */, 40C9E4FB1F2B841400753796 /* SAColorListPicker.h */, 40C9E4FC1F2B841400753796 /* SAColorListPicker.m */, 40C9E4F51F2A186A00753796 /* SARollerShutter.h */, @@ -1507,33 +1549,23 @@ 4031ACFA1BBC0FFB00CF9D8B /* MGSwipe */, 40A675801BA1BE8E004A51C4 /* SettingsVC.h */, 40A675811BA1BE8E004A51C4 /* SettingsVC.m */, - 401CA1EE1BA0923600117AF4 /* MainVC.xib */, 401CA1C61BA067DB00117AF4 /* MainVC.h */, 401CA1C71BA067DB00117AF4 /* MainVC.m */, 4017E1291BB9CE2900570AC8 /* ChannelCell.h */, 4017E12A1BB9CE2900570AC8 /* ChannelCell.m */, 407D4AFC1BC6E491009A5505 /* StatusVC.h */, 407D4AFD1BC6E491009A5505 /* StatusVC.m */, - 407D4AFE1BC6E491009A5505 /* StatusVC.xib */, 40CF96DC1BC820E60030EFFF /* UIHelper.h */, 40CF96DD1BC820E60030EFFF /* UIHelper.m */, 408034E21BC84A89007666E7 /* NavigationController.h */, 408034E31BC84A89007666E7 /* NavigationController.m */, - 408034E41BC84A89007666E7 /* NavigationController.xib */, - 40BE3E611BCA7AEF00153680 /* ChannelCell.xib */, - 01D4293922AAAA450050C1A2 /* IncrementalMeterCell.xib */, - 406778281BCBBC83008DD37F /* ThermometerCell.xib */, 406778521BCBF9F4008DD37F /* SectionCell.h */, 406778531BCBF9F4008DD37F /* SectionCell.m */, - 406778541BCBF9F4008DD37F /* SectionCell.xib */, 40DE1A331BCD1B55004CF43B /* AboutVC.h */, 40DE1A341BCD1B55004CF43B /* AboutVC.m */, - 40DE1A3A1BCD5E9B004CF43B /* AboutVC.xib */, 40B397CE1BCE7F3200BE7D5A /* Launch Screen.storyboard */, - 4038A5531CE32B6800180B5D /* TempHumidityCell.xib */, 4006E9081DC62D0A00C4456D /* DetailView.h */, 4006E9091DC62D0A00C4456D /* DetailView.m */, - 40DB208F1DC9049400FAFAB0 /* RGBDetail.xib */, 403150F91DC769430075D2D2 /* RGBDetailView.h */, 01D0616C22C294D90043C947 /* ElectricityMeterDetailView.h */, 012023C0234E54ED00E131B7 /* ImpulseCounterDetailView.h */, @@ -1541,30 +1573,19 @@ 01392B38235CA8B1003A2BAD /* ChartDetailView.h */, 01392B39235CA8B1003A2BAD /* ChartDetailView.m */, 01902A23235A17E9005ED935 /* TemperatureDetailView.h */, - 017A3C8823633A70004AD1FC /* TempHumidityDetailView.xib */, - 01902A29235A1840005ED935 /* TemperatureDetailView.xib */, 01902A24235A17E9005ED935 /* TemperatureDetailView.m */, 01902A26235A180F005ED935 /* TempHumidityDetailView.h */, 01902A27235A180F005ED935 /* TempHumidityDetailView.m */, - 019F4CAE2354DC3300286139 /* ImpulseCounterDetailView.xib */, 01D0616D22C294D90043C947 /* ElectricityMeterDetailView.m */, - 01D0617322C296850043C947 /* ElectricityMeterDetailView.xib */, - 01C8EBFC234232EC0072AB8C /* HomePlusDetailView.xib */, 403150FA1DC769430075D2D2 /* RGBDetailView.m */, - 40CE7C631DCBBCE400BBACE4 /* MeasurementCell.xib */, - 40CE7C6D1DCBBF6D00BBACE4 /* DistanceCell.xib */, 409934B41F30EF9C003110C5 /* RSDetailView.h */, 409934B51F30EF9C003110C5 /* RSDetailView.m */, - 40F951471FD0654900698587 /* RSDetail.xib */, 403EB1111FBDF47F00AD6460 /* AddWizardVC.h */, 403EB1121FBDF47F00AD6460 /* AddWizardVC.m */, - 407D31961FD1A7070062FB80 /* AddWizardVC.xib */, 4077ACE020A21BB100BD2216 /* CreateAccountVC.h */, 4077ACE120A21BB100BD2216 /* CreateAccountVC.m */, - 4077ACE220A21BB100BD2216 /* CreateAccountVC.xib */, 40B610CA20C7E263002B762A /* SAUIChannelStatus.h */, 40B610CB20C7E263002B762A /* SAUIChannelStatus.m */, - 01F9111022EF989100BFF91D /* HomePlusCell.xib */, 017554F422F1A62500EB58B7 /* HomePlusDetailView.h */, 017554F522F1A62500EB58B7 /* HomePlusDetailView.m */, 0122613722F396440013E6A2 /* SAThermostatCalendar.h */, @@ -1573,7 +1594,6 @@ 0122613822F396440013E6A2 /* SAThermostatCalendar.m */, 019D22EE233CC2D000F17135 /* SAPreloader.h */, 019D22EF233CC2D000F17135 /* SAPreloader.m */, - 01C8EBCF23422AC50072AB8C /* HomePlusDetailViewGroupCell.xib */, ); name = UI; sourceTree = ""; @@ -1707,6 +1727,7 @@ 4052DA0D1DC515AE000B8C45 /* rgb-off@2x.png in Resources */, 40CE7C6B1DCBBD5700BBACE4 /* depth@2x.png in Resources */, 40DE1A2D1BCCFF8A004CF43B /* settings@2x.png in Resources */, + 012119152368C3B2004C1993 /* collapsed@3x.png in Resources */, 405AC4341BC15C08004F7311 /* logo-supla@2x.png in Resources */, 405C49A11FCAFFD400C15602 /* wizard_ok@2x.png in Resources */, 017A3C8623633A70004AD1FC /* TempHumidityDetailView.xib in Resources */, @@ -2025,6 +2046,7 @@ 019D22F0233CC2D000F17135 /* SAPreloader.m in Sources */, 40DE1A361BCD1B55004CF43B /* AboutVC.m in Sources */, 4017E12C1BB9CE2900570AC8 /* ChannelCell.m in Sources */, + 01EFD94A236CA94400893489 /* NSData+AES.m in Sources */, 01C1719222C7F3A2005983E1 /* SAElectricityMeasurementItem+CoreDataProperties.m in Sources */, 40AB8BDE1DCB32EB0030F3DE /* SARateApp.m in Sources */, 01C1719122C7F3A2005983E1 /* SAElectricityMeasurementItem+CoreDataClass.m in Sources */, @@ -2120,6 +2142,7 @@ buildActionMask = 2147483647; files = ( 401CA1DC1BA067DB00117AF4 /* SUPLATests.m in Sources */, + 01EFD94C236CA9AE00893489 /* NSDataEncryptionTest.m in Sources */, 012F722C22DF3E2300E5F72E /* ChartFilterFieldTests.m in Sources */, 0130894523395F4C00F46FCD /* ThermostatScheduleCfgTests.m in Sources */, 012FCBD323217DE000AC6FF6 /* ThermostatCalendarTests.m in Sources */, @@ -2504,7 +2527,7 @@ "$(inherited)", "$(PROJECT_DIR)/SUPLA/lib", ); - MARKETING_VERSION = 2.3.0; + MARKETING_VERSION = 2.3.1; PRODUCT_BUNDLE_IDENTIFIER = com.acsoftware.ios.supla; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "SUPLA/SUPLA-Bridging-Header.h"; @@ -2531,7 +2554,7 @@ "$(inherited)", "$(PROJECT_DIR)/SUPLA/lib", ); - MARKETING_VERSION = 2.3.0; + MARKETING_VERSION = 2.3.1; PRODUCT_BUNDLE_IDENTIFIER = com.acsoftware.ios.supla; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OBJC_BRIDGING_HEADER = "SUPLA/SUPLA-Bridging-Header.h"; @@ -2615,12 +2638,13 @@ 407004251BB5706500F6187F /* SUPLA.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + 012119132368BDB0004C1993 /* SUPLA 5.xcdatamodel */, 01CFF6D12365BCCD00C827FB /* SUPLA 4.xcdatamodel */, 01B216CF22AECB2F004E0596 /* SUPLA 3.xcdatamodel */, 40BBA34620AC52EA0054CD20 /* SUPLA 2.xcdatamodel */, 407004261BB5706500F6187F /* SUPLA.xcdatamodel */, ); - currentVersion = 01CFF6D12365BCCD00C827FB /* SUPLA 4.xcdatamodel */; + currentVersion = 012119132368BDB0004C1993 /* SUPLA 5.xcdatamodel */; path = SUPLA.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; diff --git a/SUPLA/ChartDetailView.m b/SUPLA/ChartDetailView.m index d39d25c5..e405d327 100644 --- a/SUPLA/ChartDetailView.m +++ b/SUPLA/ChartDetailView.m @@ -103,12 +103,12 @@ -(void) runDownloadTask { } -(void) onRestApiTaskStarted: (SARestApiClientTask*)task { - NSLog(@"onRestApiTaskStarted"); + // NSLog(@"onRestApiTaskStarted"); [self.lPreloader animateWithTimeInterval:0.1]; } -(void) onRestApiTaskFinished: (SARestApiClientTask*)task { - NSLog(@"onRestApiTaskFinished"); + // NSLog(@"onRestApiTaskFinished"); if (_task != nil && task == _task) { _task.delegate = nil; _task = nil; diff --git a/SUPLA/Database.h b/SUPLA/Database.h index 10ffcb45..e925394a 100644 --- a/SUPLA/Database.h +++ b/SUPLA/Database.h @@ -61,6 +61,7 @@ typedef NS_ENUM(NSUInteger, GroupBy) { - (void)saveContext; -(_SALocation*) fetchLocationById:(int)location_id; +-(NSArray*) fetchVisibleLocations; -(_SALocation*) newLocation; -(BOOL) updateLocation:(TSC_SuplaLocation *)location; diff --git a/SUPLA/Database.m b/SUPLA/Database.m index 1685f403..b10fd9e4 100644 --- a/SUPLA/Database.m +++ b/SUPLA/Database.m @@ -62,7 +62,7 @@ - (NSPersistentStoreCoordinator *)persistentStoreCoordinator { return _persistentStoreCoordinator; } - int DBv = 7; + int DBv = 8; [self removeIfExists:@"SUPLA_DB.sqlite"]; @@ -250,6 +250,10 @@ -(_SALocation*) fetchLocationById:(int)location_id { return [self fetchItemByPredicate:[NSPredicate predicateWithFormat:@"location_id = %i", location_id] entityName:@"SALocation"]; }; +-(NSArray*) fetchVisibleLocations { + return [self fetchByPredicate:[NSPredicate predicateWithFormat:@"visible > 0"] entityName:@"SALocation" limit:0 sortDescriptors:nil]; +} + -(_SALocation*) newLocation { _SALocation *Location = [[_SALocation alloc] initWithEntity:[NSEntityDescription entityForName:@"SALocation" inManagedObjectContext:self.managedObjectContext] insertIntoManagedObjectContext:self.managedObjectContext]; @@ -1334,7 +1338,6 @@ -(void) deleteAllUserIcons { del = YES; for(int a=0;a #import "SADownloadUserIcons.h" +#import "SectionCell.h" @class SADetailView; -@interface SAMainVC : UIViewController +@interface SAMainVC : UIViewController - (IBAction)settingsTouched:(id)sender; @@ -34,7 +35,7 @@ @property (weak, nonatomic) IBOutlet UILabel *notificationLabel; - (void)detailHide; - +- (void)groupTableHidden:(BOOL)hidden; @end diff --git a/SUPLA/MainVC.m b/SUPLA/MainVC.m index f46a6153..94764811 100644 --- a/SUPLA/MainVC.m +++ b/SUPLA/MainVC.m @@ -22,7 +22,6 @@ #import "SuplaApp.h" #import "Database.h" #import "SAChannel+CoreDataClass.h" -#import "SectionCell.h" #import "RGBDetailView.h" #import "RSDetailView.h" #import "ElectricityMeterDetailView.h" @@ -31,6 +30,7 @@ #import "TemperatureDetailView.h" #import "TempHumidityDetailView.h" #import "SARateApp.h" +#import "_SALocation+CoreDataClass.h" @implementation SAMainVC { NSFetchedResultsController *_cFrc; @@ -46,7 +46,7 @@ @implementation SAMainVC { NSTimer *_nTimer; UITapGestureRecognizer *_tapRecognizer; SADownloadUserIcons *_task; - + NSArray *_locations; } - (void)registerNibForTableView:(UITableView*)tv { @@ -104,6 +104,8 @@ - (void)didReceiveMemoryWarning { -(void)onDataChanged { _cFrc = nil; _gFrc = nil; + _locations = nil; + [self.cTableView reloadData]; [self.gTableView reloadData]; } @@ -231,6 +233,27 @@ - (void)detailHide { [(SAMainView*)self.view detailShow:NO animated:NO]; } +#pragma mark Locations + +- (_SALocation *) locationByName:(NSString *)name { + if (name == nil) { + return nil; + } + + if (_locations == nil) { + _locations = [SAApp.DB fetchVisibleLocations]; + if (_locations == nil) { + _locations = [[NSArray alloc] init]; + } + } + + NSUInteger idx = [_locations indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) { + return [((_SALocation*)obj).caption isEqualToString:name]; + }]; + + return idx == NSNotFound ? nil : (_SALocation*)[_locations objectAtIndex:idx]; +} + #pragma mark Table Support - (NSFetchedResultsController*)frcForTableView:(UITableView*)tableView { @@ -261,16 +284,42 @@ - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInte return [[[[self frcForTableView:tableView] sections] objectAtIndex:section] name]; } +- (short)bitFlagCollapse { + return self.cTableView.hidden == NO ? 0x1 : 0x2; +} + - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { + NSFetchedResultsController *frc = [self frcForTableView:tableView]; if ( frc ) { id sectionInfo = [[frc sections] objectAtIndex:section]; + _SALocation *location = [self locationByName:sectionInfo.name]; + if (location != nil + && (location.collapsed & [self bitFlagCollapse]) > 0) { + return 0; + } return [sectionInfo numberOfObjects]; } return 0; } +- (void)sectionCellTouch:(SASectionCell*)section { + + _SALocation *location = [self locationByName:section.label.text]; + if (location) { + short bit = [self bitFlagCollapse]; + if ((location.collapsed & bit) > 0) { + location.collapsed ^= bit; + } else { + location.collapsed |= bit; + } + + [SAApp.DB saveContext]; + [self onDataChanged]; + } +} + - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { SAChannelBase *channel_base = [[self frcForTableView:tableView] objectAtIndexPath:indexPath]; @@ -320,9 +369,12 @@ -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger) { SASectionCell *cell = [tableView dequeueReusableCellWithIdentifier:@"SectionCell"]; if ( cell ) { - [cell.label setText:[[[[self frcForTableView:tableView] sections] objectAtIndex:section] name]]; + NSString *name = [[[[self frcForTableView:tableView] sections] objectAtIndex:section] name]; + _SALocation *location = [self locationByName:name]; + cell.ivCollapsed.hidden = location == nil || (location.collapsed & [self bitFlagCollapse]) == 0; + [cell.label setText:name]; + cell.delegate = self; } - return cell; } @@ -331,6 +383,13 @@ - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSIntege return 50; } +- (void)groupTableHidden:(BOOL)hidden { + self.cTableView.hidden = !hidden; + self.gTableView.hidden = hidden; + + [self onDataChanged]; +} + - (IBAction)settingsTouched:(id)sender { [[SAApp UI ] showSettings]; @@ -357,11 +416,11 @@ -(void)runDownloadTask { } -(void) onRestApiTaskStarted: (SARestApiClientTask*)task { - NSLog(@"onRestApiTaskStarted"); + // NSLog(@"onRestApiTaskStarted"); } -(void) onRestApiTaskFinished: (SARestApiClientTask*)task { - NSLog(@"onRestApiTaskFinished"); + // NSLog(@"onRestApiTaskFinished"); if (_task != nil && task == _task) { if (_task.channelsUpdated) { [self onDataChanged]; @@ -409,7 +468,6 @@ -(void)initMainView { _animating = NO; _panRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)]; [self addGestureRecognizer:_panRecognizer]; - } -(SADetailView*)detailView { @@ -638,12 +696,9 @@ - (void)detailShow:(BOOL)show animated:(BOOL)animated { } } - - } - - (void)handlePan:(UIPanGestureRecognizer *)gr { if ( _animating ) @@ -724,5 +779,18 @@ -(void)moveCenter:(float)x_offset { [self setCenter:CGPointMake(self.center.x+x_offset, self.center.y)]; } +- (void)handleTap:(UITapGestureRecognizer *)gr { + if ( _animating ) + return; + + UITableView *tableView = self.cTableView.hidden ? self.gTableView : self.cTableView; + CGPoint touch_point = [gr locationInView:tableView]; + NSIndexPath *path = [tableView indexPathForRowAtPoint:touch_point]; + + SASectionCell *section = [tableView cellForRowAtIndexPath:path]; + if ([section isKindOfClass:[SASectionCell class]]) { + + } +} @end diff --git a/SUPLA/NSData+AES.h b/SUPLA/NSData+AES.h new file mode 100644 index 00000000..14c59ef5 --- /dev/null +++ b/SUPLA/NSData+AES.h @@ -0,0 +1,31 @@ +/* +Copyright (C) AC SOFTWARE SP. Z O.O. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface NSData (AES) +- (NSData *)aes128EncryptWithPassword:(NSString *)password; +- (NSData *)aes128DecryptWithPassword:(NSString *)password; + +- (NSData *)aes128EncryptWithDeviceUniqueId; +- (NSData *)aes128DecryptWithDeviceUniqueId; +@end + +NS_ASSUME_NONNULL_END diff --git a/SUPLA/NSData+AES.m b/SUPLA/NSData+AES.m new file mode 100644 index 00000000..21ec1361 --- /dev/null +++ b/SUPLA/NSData+AES.m @@ -0,0 +1,79 @@ +/* +Copyright (C) AC SOFTWARE SP. Z O.O. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#import "NSData+AES.h" +#import +#import + +@implementation NSData (AES) + +-(NSData *)aes128Operation:(CCOperation)operation withPassword:(NSString *)password { + + // *Password + // This is not a good implementation but sufficient for current use + while(password.length < 32) { + password = [NSString stringWithFormat:@"%@0", password]; + } + + password = [password substringToIndex:32]; + + size_t bufferSize = [self length] + kCCBlockSizeAES128; + void *buffer = malloc(bufferSize); + + NSData *_key = [password dataUsingEncoding:NSUTF8StringEncoding]; + + size_t encryptedSize = 0; + CCCryptorStatus cryptStatus = CCCrypt(operation, + kCCAlgorithmAES128, + kCCOptionPKCS7Padding, + [_key bytes], + [_key length], + nil, + [self bytes], + [self length], + buffer, + bufferSize, + &encryptedSize); + + if (cryptStatus == kCCSuccess && encryptedSize > 0) { + return [NSData dataWithBytesNoCopy:buffer length:encryptedSize]; + } + + free(buffer); + return nil; +} + +- (NSData *)aes128EncryptWithPassword:(NSString *)password { + return [self aes128Operation:kCCEncrypt withPassword:password]; +} + +- (NSData *)aes128DecryptWithPassword:(NSString *)password { + return [self aes128Operation:kCCDecrypt withPassword:password]; +} + +- (NSData *)aes128EncryptWithDeviceUniqueId { + NSString *pwd = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; + return [self aes128EncryptWithPassword:pwd]; +} + +- (NSData *)aes128DecryptWithDeviceUniqueId { + NSString *pwd = [[[UIDevice currentDevice] identifierForVendor] UUIDString]; + return [self aes128DecryptWithPassword:pwd]; + +} +@end diff --git a/SUPLA/NavigationController.m b/SUPLA/NavigationController.m index 8f35e534..80bad274 100644 --- a/SUPLA/NavigationController.m +++ b/SUPLA/NavigationController.m @@ -212,13 +212,11 @@ - (IBAction)groupsTouch:(id)sender { if ( self.btnGroups.tag == 1 ) { [self.btnGroups setImage:[UIImage imageNamed:@"groupsoff.png"]]; self.btnGroups.tag = 0; - MainVC.cTableView.hidden = NO; - MainVC.gTableView.hidden = YES; + [MainVC groupTableHidden: YES]; } else { [self.btnGroups setImage:[UIImage imageNamed:@"groupson.png"]]; self.btnGroups.tag = 1; - MainVC.cTableView.hidden = YES; - MainVC.gTableView.hidden = NO; + [MainVC groupTableHidden: NO]; } } diff --git a/SUPLA/Resources/Assets/Img/collapsed@3x.png b/SUPLA/Resources/Assets/Img/collapsed@3x.png new file mode 100644 index 00000000..89d3f8e5 Binary files /dev/null and b/SUPLA/Resources/Assets/Img/collapsed@3x.png differ diff --git a/SUPLA/SAChannelBase+CoreDataClass.m b/SUPLA/SAChannelBase+CoreDataClass.m index e13593d5..953f9fa0 100644 --- a/SUPLA/SAChannelBase+CoreDataClass.m +++ b/SUPLA/SAChannelBase+CoreDataClass.m @@ -349,9 +349,6 @@ - (UIImage*) getIconWithIndex:(short)idx { UIImage *img = nil; @try { - if (self.remote_id == 127) { - NSLog(@"%@", self.usericon); - } if (data != nil && [data isKindOfClass:[NSData class]]) { img = [UIImage imageWithData:(NSData*)data]; } diff --git a/SUPLA/SUPLA.xcdatamodeld/.xccurrentversion b/SUPLA/SUPLA.xcdatamodeld/.xccurrentversion index 2c8560c4..5f761ffa 100644 --- a/SUPLA/SUPLA.xcdatamodeld/.xccurrentversion +++ b/SUPLA/SUPLA.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - SUPLA 4.xcdatamodel + SUPLA 5.xcdatamodel diff --git a/SUPLA/SUPLA.xcdatamodeld/SUPLA 5.xcdatamodel/contents b/SUPLA/SUPLA.xcdatamodeld/SUPLA 5.xcdatamodel/contents new file mode 100644 index 00000000..0b9e6673 --- /dev/null +++ b/SUPLA/SUPLA.xcdatamodeld/SUPLA 5.xcdatamodel/contents @@ -0,0 +1,146 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SUPLA/SectionCell.h b/SUPLA/SectionCell.h index 28fa1402..e2acb9ad 100644 --- a/SUPLA/SectionCell.h +++ b/SUPLA/SectionCell.h @@ -18,7 +18,14 @@ #import +@class SASectionCell; +@protocol SASectionCellDelegate +@optional +- (void)sectionCellTouch:(SASectionCell*)section; +@end + @interface SASectionCell : UITableViewCell +@property (weak, nonatomic) IBOutlet UIImageView *ivCollapsed; @property (weak, nonatomic) IBOutlet UILabel *label; - +@property (nonatomic, weak, nullable) id delegate; @end diff --git a/SUPLA/SectionCell.m b/SUPLA/SectionCell.m index 914a6d2b..4adc43ef 100644 --- a/SUPLA/SectionCell.m +++ b/SUPLA/SectionCell.m @@ -18,13 +18,38 @@ #import "SectionCell.h" -@implementation SASectionCell +@implementation SASectionCell { + UITapGestureRecognizer *_tap; +} +- (void)initialize { + if (_tap == nil) { + _tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapped:)]; + _tap.delegate = self; + [self addGestureRecognizer:_tap]; + } +} -- (void)setSelected:(BOOL)selected animated:(BOOL)animated { - [super setSelected:selected animated:animated]; +- (id)initWithCoder:(NSCoder *)coder +{ + self = [super initWithCoder:coder]; + if (self) { + [self initialize]; + } + return self; +} - // Configure the view for the selected state +- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(nullable NSString *)reuseIdentifier { + self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; + if (self) { + [self initialize]; + } + return self; } +- (void)tapped:(UITapGestureRecognizer *)gr { + if (self.delegate) { + [self.delegate sectionCellTouch:self]; + } +} @end diff --git a/SUPLA/SectionCell.xib b/SUPLA/SectionCell.xib index eedbbf7a..0961f9a2 100644 --- a/SUPLA/SectionCell.xib +++ b/SUPLA/SectionCell.xib @@ -1,13 +1,13 @@ - - + + + - - + - + Quicksand-Regular @@ -18,35 +18,50 @@ - + + + - + + + + - + + + + diff --git a/SUPLA/_SALocation+CoreDataProperties.h b/SUPLA/_SALocation+CoreDataProperties.h index 067b9965..d0274d7a 100644 --- a/SUPLA/_SALocation+CoreDataProperties.h +++ b/SUPLA/_SALocation+CoreDataProperties.h @@ -1,20 +1,20 @@ /* - Copyright (C) AC SOFTWARE SP. Z O.O. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ +Copyright (C) AC SOFTWARE SP. Z O.O. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ #import "_SALocation+CoreDataClass.h" @@ -28,6 +28,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nullable, nonatomic, copy) NSString *caption; @property (nullable, nonatomic, copy) NSNumber *location_id; @property (nullable, nonatomic, copy) NSNumber *visible; +@property (nonatomic) int16_t collapsed; @end diff --git a/SUPLA/_SALocation+CoreDataProperties.m b/SUPLA/_SALocation+CoreDataProperties.m index 090c28aa..2293ca0f 100644 --- a/SUPLA/_SALocation+CoreDataProperties.m +++ b/SUPLA/_SALocation+CoreDataProperties.m @@ -1,31 +1,32 @@ /* - Copyright (C) AC SOFTWARE SP. Z O.O. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - */ +Copyright (C) AC SOFTWARE SP. Z O.O. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ #import "_SALocation+CoreDataProperties.h" @implementation _SALocation (CoreDataProperties) + (NSFetchRequest<_SALocation *> *)fetchRequest { - return [[NSFetchRequest alloc] initWithEntityName:@"SALocation"]; + return [NSFetchRequest fetchRequestWithEntityName:@"SALocation"]; } @dynamic caption; @dynamic location_id; @dynamic visible; +@dynamic collapsed; @end diff --git a/SUPLATests/NSDataEncryptionTest.m b/SUPLATests/NSDataEncryptionTest.m new file mode 100644 index 00000000..13ef7a4b --- /dev/null +++ b/SUPLATests/NSDataEncryptionTest.m @@ -0,0 +1,57 @@ +/* +Copyright (C) AC SOFTWARE SP. Z O.O. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#import +#import "NSData+AES.h" + +@interface NSDataEncryptionTest : XCTestCase + +@end + +@implementation NSDataEncryptionTest + +- (void)testEncryption { + + NSString *sourceText = @"ABCD"; + NSData *sourceData = [sourceText dataUsingEncoding:NSUTF8StringEncoding]; + + // Key is aligned to 32 characters + NSData *encrypted = [sourceData aes128EncryptWithPassword:@"X"]; + XCTAssertNotNil(encrypted); + XCTAssertFalse([encrypted isEqualToData:sourceData]); + + NSData *decrypted = [encrypted aes128DecryptWithPassword:@"X"]; + XCTAssertNotNil(decrypted); + XCTAssertFalse([encrypted isEqualToData:decrypted]); + XCTAssertTrue([decrypted isEqualToData:sourceData]); + + NSString *decryptedText = [[NSString alloc] + initWithData:decrypted encoding:NSUTF8StringEncoding]; + XCTAssertTrue([decryptedText isEqualToString:sourceText]); + + decrypted = [encrypted aes128DecryptWithPassword:@"Y"]; + XCTAssertFalse([sourceData isEqualToData:decrypted]); + + decrypted = [encrypted aes128DecryptWithPassword:@"X000000000000000000000000000000Y"]; + XCTAssertFalse([sourceData isEqualToData:decrypted]); + + decrypted = [encrypted aes128DecryptWithPassword:@"X0000000000000000000000000000000Y"]; + XCTAssertTrue([sourceData isEqualToData:decrypted]); +} + +@end diff --git a/SuplaApp.m b/SuplaApp.m index 7bfdd551..1a9c1811 100644 --- a/SuplaApp.m +++ b/SuplaApp.m @@ -19,7 +19,7 @@ #import "SuplaApp.h" #import "Database.h" - +#import "NSData+AES.h" static SAApp* _Globals = nil; @@ -80,25 +80,39 @@ +(SAApp*)instance { return _Globals; } -+(void) getRandomKey:(char*)key keySize:(int)size forPrefKey:(NSString*)pref_key { +-(void) encryptData:(NSData *)data andSaveWithPrefKey:(NSString *)pref_key { + @synchronized(self) { + NSData *encryptedData = [data aes128EncryptWithDeviceUniqueId]; + NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; + [ud setValue:(encryptedData != nil ? encryptedData : data) forKey:pref_key]; + [ud setBool:(encryptedData != nil) forKey:[NSString stringWithFormat:@"%@_encrypted", pref_key]]; + } +} + +-(void) getRandom:(char*)key size:(int)size forPrefKey:(NSString*)pref_key { @synchronized(self) { + NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:pref_key]; + + if ([[NSUserDefaults standardUserDefaults] boolForKey:[NSString stringWithFormat:@"%@_encrypted", pref_key]]) { + data = [data aes128DecryptWithDeviceUniqueId]; + } else { + [self encryptData:data andSaveWithPrefKey:pref_key]; + } - NSData *KEY = [[NSUserDefaults standardUserDefaults] dataForKey:pref_key]; - if ( KEY == nil || [KEY length] != size ) { - - NSMutableData* newKEY = [NSMutableData dataWithCapacity:size]; + if ( data == nil || [data length] != size ) { + NSMutableData* newRandomData = [NSMutableData dataWithCapacity:size]; for( int i = 0 ; i < size; ++i ) { Byte random = arc4random(); - [newKEY appendBytes:(void*)&random length:1]; + [newRandomData appendBytes:(void*)&random length:1]; } - [[NSUserDefaults standardUserDefaults] setValue:newKEY forKey:pref_key]; - KEY = newKEY; + [self encryptData:newRandomData andSaveWithPrefKey:pref_key]; + data = newRandomData; }; - if ( KEY && [KEY length] == size ) { - [KEY getBytes:key length:size]; + if ( data && [data length] == size ) { + [data getBytes:key length:size]; } else { memset(key, 0, size); } @@ -108,12 +122,11 @@ +(void) getRandomKey:(char*)key keySize:(int)size forPrefKey:(NSString*)pref_key } +(void) getClientGUID:(char[SUPLA_GUID_SIZE])guid { - // TODO: Implement guid encryption with password based on device id - [SAApp getRandomKey:guid keySize:SUPLA_GUID_SIZE forPrefKey:@"client_guid"]; + [[self instance] getRandom:guid size:SUPLA_GUID_SIZE forPrefKey:@"client_guid"]; } +(void) getAuthKey:(char [SUPLA_AUTHKEY_SIZE])auth_key { - [SAApp getRandomKey:auth_key keySize:SUPLA_AUTHKEY_SIZE forPrefKey:@"auth_key"]; + [[self instance] getRandom:auth_key size:SUPLA_AUTHKEY_SIZE forPrefKey:@"auth_key"]; } -(int) getCfgVersion {