diff --git a/.gitignore b/.gitignore index d274feb..85fa3a2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +iOSInjectionProject/ .DS_Store # Xcode # @@ -20,3 +21,4 @@ DerivedData Carthage/Checkouts Carthage/Build +Cartfile.resolved diff --git a/BodyweightFitness.xcodeproj/project.pbxproj b/BodyweightFitness.xcodeproj/project.pbxproj index 1103c4d..a088402 100755 --- a/BodyweightFitness.xcodeproj/project.pbxproj +++ b/BodyweightFitness.xcodeproj/project.pbxproj @@ -7,27 +7,27 @@ objects = { /* Begin PBXBuildFile section */ + 46B021B6A56C2000CA08000B /* WorkoutLogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46B02AEDB4B0B259C2EAE1E8 /* WorkoutLogViewController.swift */; }; 46B02780EEC08B16FB384A4F /* CardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 46B020C26FAF7645B926FA26 /* CardView.swift */; }; 732BA01F1C5ADC1200C1CDB5 /* PageMenuFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 732BA01E1C5ADC1200C1CDB5 /* PageMenuFramework.framework */; }; 732BA0221C5ADC3100C1CDB5 /* PageMenuFramework.framework.dSYM in CopyFiles */ = {isa = PBXBuildFile; fileRef = 732BA0211C5ADC3100C1CDB5 /* PageMenuFramework.framework.dSYM */; }; 732BA0241C5AE75900C1CDB5 /* ProgressPageViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 732BA0231C5AE75900C1CDB5 /* ProgressPageViewController.xib */; }; - 732BA0261C5AE8EF00C1CDB5 /* CardViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 732BA0251C5AE8EF00C1CDB5 /* CardViewCell.xib */; }; - 732BA0281C5AE8F900C1CDB5 /* SectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 732BA0271C5AE8F900C1CDB5 /* SectionViewCell.xib */; }; - 732BA02A1C5B76DD00C1CDB5 /* CardViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 732BA0291C5B76DD00C1CDB5 /* CardViewCell.swift */; }; - 732BA02C1C5B76E500C1CDB5 /* SectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 732BA02B1C5B76E500C1CDB5 /* SectionViewCell.swift */; }; + 732BA0261C5AE8EF00C1CDB5 /* ProgressCardCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 732BA0251C5AE8EF00C1CDB5 /* ProgressCardCell.xib */; }; + 732BA0281C5AE8F900C1CDB5 /* ProgressSectionCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 732BA0271C5AE8F900C1CDB5 /* ProgressSectionCell.xib */; }; + 732BA02A1C5B76DD00C1CDB5 /* ProgressCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 732BA0291C5B76DD00C1CDB5 /* ProgressCardCell.swift */; }; + 732BA02C1C5B76E500C1CDB5 /* ProgressSectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 732BA02B1C5B76E500C1CDB5 /* ProgressSectionCell.swift */; }; 732BA02E1C5B7A8D00C1CDB5 /* ProgressGeneralViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 732BA02D1C5B7A8D00C1CDB5 /* ProgressGeneralViewController.xib */; }; 732BA03D1C5BC9D400C1CDB5 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 732BA03C1C5BC9D400C1CDB5 /* LaunchScreen.xib */; }; - 732BA0431C5EB9C300C1CDB5 /* CalendarCardViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 732BA0421C5EB9C300C1CDB5 /* CalendarCardViewCell.swift */; }; - 732BA0451C5EB9CE00C1CDB5 /* CalendarCardViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 732BA0441C5EB9CE00C1CDB5 /* CalendarCardViewCell.xib */; }; - 732BA0471C5EBB9900C1CDB5 /* CalendarSectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 732BA0461C5EBB9900C1CDB5 /* CalendarSectionViewCell.xib */; }; - 732BA0491C5EBBA400C1CDB5 /* CalendarSectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 732BA0481C5EBBA400C1CDB5 /* CalendarSectionViewCell.swift */; }; + 732BA0431C5EB9C300C1CDB5 /* WorkoutLogCardCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 732BA0421C5EB9C300C1CDB5 /* WorkoutLogCardCell.swift */; }; + 732BA0451C5EB9CE00C1CDB5 /* WorkoutLogCardCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 732BA0441C5EB9CE00C1CDB5 /* WorkoutLogCardCell.xib */; }; + 732BA0471C5EBB9900C1CDB5 /* WorkoutLogSectionCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 732BA0461C5EBB9900C1CDB5 /* WorkoutLogSectionCell.xib */; }; + 732BA0491C5EBBA400C1CDB5 /* WorkoutLogSectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 732BA0481C5EBBA400C1CDB5 /* WorkoutLogSectionCell.swift */; }; 733876D51C4AB163006AABA7 /* LogWorkoutButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 733876D41C4AB163006AABA7 /* LogWorkoutButton.swift */; }; 733876DA1C4ABF88006AABA7 /* RoutineStream.swift in Sources */ = {isa = PBXBuildFile; fileRef = 733876D91C4ABF88006AABA7 /* RoutineStream.swift */; }; 733876DE1C4AC829006AABA7 /* Runes.framework.dSYM in CopyFiles */ = {isa = PBXBuildFile; fileRef = 733876DC1C4AC829006AABA7 /* Runes.framework.dSYM */; }; 733876DF1C4AC829006AABA7 /* SwiftyJSON.framework.dSYM in CopyFiles */ = {isa = PBXBuildFile; fileRef = 733876DD1C4AC829006AABA7 /* SwiftyJSON.framework.dSYM */; }; 7349F6A31C492729009DBE7B /* Runes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7349F6A11C492729009DBE7B /* Runes.framework */; }; 734B6F3F1C4AE7E900CFB6BD /* LogWorkoutController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 734B6F3E1C4AE7E900CFB6BD /* LogWorkoutController.swift */; }; - 734B6F421C4BAC6A00CFB6BD /* CalendarViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 734B6F411C4BAC6A00CFB6BD /* CalendarViewController.swift */; }; 734B6FB11C4BB73D00CFB6BD /* CVAuxiliaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 734B6F961C4BB73D00CFB6BD /* CVAuxiliaryView.swift */; }; 734B6FB31C4BB73D00CFB6BD /* CVCalendarContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 734B6F971C4BB73D00CFB6BD /* CVCalendarContentViewController.swift */; }; 734B6FB51C4BB73D00CFB6BD /* CVCalendarDayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 734B6F981C4BB73D00CFB6BD /* CVCalendarDayView.swift */; }; @@ -64,6 +64,9 @@ 734B70051C4BF7C700CFB6BD /* RepositoryRoutine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 734B70041C4BF7C700CFB6BD /* RepositoryRoutine.swift */; }; 734B70081C4BF7DD00CFB6BD /* RepositoryCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 734B70071C4BF7DD00CFB6BD /* RepositoryCategory.swift */; }; 734B700B1C4BF7E900CFB6BD /* RepositorySection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 734B700A1C4BF7E900CFB6BD /* RepositorySection.swift */; }; + 735BEA071CBD1E56003616C5 /* SideView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 735BEA061CBD1E56003616C5 /* SideView.xib */; }; + 735BEA0A1CBD1F38003616C5 /* SideViewHeaderCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 735BEA091CBD1F38003616C5 /* SideViewHeaderCell.xib */; }; + 735BEA0C1CBD1F5E003616C5 /* SideViewMenuCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 735BEA0B1CBD1F5E003616C5 /* SideViewMenuCell.xib */; }; 7366D8D11C4EE9CC00819790 /* ProgressViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7366D8D01C4EE9CC00819790 /* ProgressViewController.swift */; }; 7366D8DD1C4EEFD500819790 /* ProgressPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7366D8DC1C4EEFD500819790 /* ProgressPageViewController.swift */; }; 7366D8E11C51810600819790 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7366D8E01C51810600819790 /* Extensions.swift */; }; @@ -71,25 +74,44 @@ 7366D8E81C51AD9C00819790 /* SwiftCharts.framework.dSYM in CopyFiles */ = {isa = PBXBuildFile; fileRef = 7366D8E61C51AD9600819790 /* SwiftCharts.framework.dSYM */; }; 7366D8EA1C52416C00819790 /* SupportDeveloperViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7366D8E91C52416C00819790 /* SupportDeveloperViewController.swift */; }; 7366D8ED1C52943D00819790 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7366D8EC1C52943D00819790 /* StoreKit.framework */; }; + 737F3C781CBD52AB00251EFE /* WorkoutLogView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 737F3C771CBD52AB00251EFE /* WorkoutLogView.xib */; }; 737F3C801CBE4A1800251EFE /* ring_wide_pushup.gif in Resources */ = {isa = PBXBuildFile; fileRef = 737F3C7F1CBE4A1800251EFE /* ring_wide_pushup.gif */; }; 73AA28EA1CABE69200DEED79 /* DashboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73AA28E91CABE69200DEED79 /* DashboardViewController.swift */; }; 73AA28ED1CABE8F800DEED79 /* DashboardView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73AA28EC1CABE8F800DEED79 /* DashboardView.xib */; }; - 73AA28EF1CB7ABB500DEED79 /* DashboardSectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73AA28EE1CB7ABB500DEED79 /* DashboardSectionViewCell.xib */; }; - 73AA28F11CB7ABC300DEED79 /* DashboardSectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73AA28F01CB7ABC300DEED79 /* DashboardSectionViewCell.swift */; }; - 73AA28F31CB7ACC100DEED79 /* DashboardCategoryViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73AA28F21CB7ACC100DEED79 /* DashboardCategoryViewCell.swift */; }; - 73AA28F51CB7ACCC00DEED79 /* DashboardCategoryViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73AA28F41CB7ACCC00DEED79 /* DashboardCategoryViewCell.xib */; }; - 73AA28F71CB7ACD900DEED79 /* DashboardSingleItemViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73AA28F61CB7ACD900DEED79 /* DashboardSingleItemViewCell.xib */; }; - 73AA28F91CB7ACE300DEED79 /* DashboardDoubleItemViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73AA28F81CB7ACE300DEED79 /* DashboardDoubleItemViewCell.xib */; }; - 73AA28FB1CB7ACEB00DEED79 /* DashboardSingleItemViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73AA28FA1CB7ACEB00DEED79 /* DashboardSingleItemViewCell.swift */; }; - 73AA28FD1CB7ACF500DEED79 /* DashboardDoubleItemViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73AA28FC1CB7ACF500DEED79 /* DashboardDoubleItemViewCell.swift */; }; - 73BFEBB81CBA889400B9DDAE /* Material.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73BFEBB71CBA889400B9DDAE /* Material.framework */; }; - 73BFEBBB1CBA8A5F00B9DDAE /* Material.framework.dSYM in CopyFiles */ = {isa = PBXBuildFile; fileRef = 73BFEBB91CBA8A4700B9DDAE /* Material.framework.dSYM */; }; - 73BFEBBE1CBAC94300B9DDAE /* WeightUnitCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73BFEBBD1CBAC94300B9DDAE /* WeightUnitCell.swift */; }; - 73BFEBC01CBAE19A00B9DDAE /* DevelopedByCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73BFEBBF1CBAE19A00B9DDAE /* DevelopedByCell.swift */; }; - 73BFEBC21CBAEDD800B9DDAE /* SnackBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73BFEBC11CBAEDD800B9DDAE /* SnackBar.swift */; }; + 73AA28EF1CB7ABB500DEED79 /* DashboardSectionCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73AA28EE1CB7ABB500DEED79 /* DashboardSectionCell.xib */; }; + 73AA28F11CB7ABC300DEED79 /* DashboardSectionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73AA28F01CB7ABC300DEED79 /* DashboardSectionCell.swift */; }; + 73AA28F31CB7ACC100DEED79 /* DashboardCategoryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73AA28F21CB7ACC100DEED79 /* DashboardCategoryCell.swift */; }; + 73AA28F51CB7ACCC00DEED79 /* DashboardCategoryCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73AA28F41CB7ACCC00DEED79 /* DashboardCategoryCell.xib */; }; + 73AA28F71CB7ACD900DEED79 /* DashboardSingleItemCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73AA28F61CB7ACD900DEED79 /* DashboardSingleItemCell.xib */; }; + 73AA28F91CB7ACE300DEED79 /* DashboardDoubleItemCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73AA28F81CB7ACE300DEED79 /* DashboardDoubleItemCell.xib */; }; + 73AA28FB1CB7ACEB00DEED79 /* DashboardSingleItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73AA28FA1CB7ACEB00DEED79 /* DashboardSingleItemCell.swift */; }; + 73AA28FD1CB7ACF500DEED79 /* DashboardDoubleItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73AA28FC1CB7ACF500DEED79 /* DashboardDoubleItemCell.swift */; }; + 73BADE151CC3DC26001ACEDC /* RateMyApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73BADE141CC3DC26001ACEDC /* RateMyApp.swift */; }; + 73BADE171CC3E2F9001ACEDC /* TimedView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73BADE161CC3E2F9001ACEDC /* TimedView.xib */; }; + 73BADE191CC3E347001ACEDC /* TimedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73BADE181CC3E347001ACEDC /* TimedViewController.swift */; }; + 73BADE1B1CC3F956001ACEDC /* WeightedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73BADE1A1CC3F956001ACEDC /* WeightedViewController.swift */; }; + 73BADE1D1CC3F98D001ACEDC /* WeightedView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73BADE1C1CC3F98D001ACEDC /* WeightedView.xib */; }; + 73BADE251CC6EE94001ACEDC /* shoulder_rolls.gif in Resources */ = {isa = PBXBuildFile; fileRef = 73BADE241CC6EE94001ACEDC /* shoulder_rolls.gif */; }; + 73BADE271CC6F19E001ACEDC /* band_pull_downs.gif in Resources */ = {isa = PBXBuildFile; fileRef = 73BADE261CC6F19E001ACEDC /* band_pull_downs.gif */; }; + 73BADE291CC6F480001ACEDC /* band_chest_flies.gif in Resources */ = {isa = PBXBuildFile; fileRef = 73BADE281CC6F480001ACEDC /* band_chest_flies.gif */; }; + 73BADE6E1CC78356001ACEDC /* BodyweightFitnessTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73BADE6D1CC78356001ACEDC /* BodyweightFitnessTests.swift */; }; + 73BADE7D1CC79648001ACEDC /* TestRoutine.json in Resources */ = {isa = PBXBuildFile; fileRef = 73BADE7C1CC79648001ACEDC /* TestRoutine.json */; }; + 73BF3BA91CBE643200E0258D /* SettingsView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73BF3BA81CBE643200E0258D /* SettingsView.xib */; }; + 73BF3BAD1CBE6A5D00E0258D /* SettingsToggleCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73BF3BAC1CBE6A5D00E0258D /* SettingsToggleCell.xib */; }; + 73BF3BAF1CBE6A7000E0258D /* SettingsActionCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73BF3BAE1CBE6A7000E0258D /* SettingsActionCell.xib */; }; + 73BF3BB11CBE6A8000E0258D /* SettingsTextCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73BF3BB01CBE6A8000E0258D /* SettingsTextCell.xib */; }; + 73BF3BB31CBE819B00E0258D /* SettingsActionSubtitleCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73BF3BB21CBE819B00E0258D /* SettingsActionSubtitleCell.xib */; }; + 73BF3BB51CBEB08B00E0258D /* LogWorkoutModalView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73BF3BB41CBEB08B00E0258D /* LogWorkoutModalView.xib */; }; + 73BF3BB91CBEFB0E00E0258D /* RootView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73BF3BB81CBEFB0E00E0258D /* RootView.xib */; }; + 73BF3BBB1CBEFB1E00E0258D /* RootViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73BF3BBA1CBEFB1E00E0258D /* RootViewController.swift */; }; + 73BF3BBF1CBF02D200E0258D /* Window.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73BF3BBE1CBF02D200E0258D /* Window.xib */; }; + 73BF3BC11CBF05ED00E0258D /* SnackBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73BF3BC01CBF05ED00E0258D /* SnackBar.swift */; }; + 73BF3BC71CBFF89D00E0258D /* NavigationView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73BF3BC61CBFF89D00E0258D /* NavigationView.xib */; }; + 73BF3BC91CBFFF0A00E0258D /* NavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73BF3BC81CBFFF0A00E0258D /* NavigationViewController.swift */; }; 73BFEBC41CBBFA3900B9DDAE /* SupportDeveloperView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 73BFEBC31CBBFA3900B9DDAE /* SupportDeveloperView.xib */; }; 73BFEC061CBC2C9A00B9DDAE /* Fabric.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73BFEC041CBC2C9A00B9DDAE /* Fabric.framework */; }; 73BFEC071CBC2C9A00B9DDAE /* Crashlytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73BFEC051CBC2C9A00B9DDAE /* Crashlytics.framework */; }; + 73C5A6371CC12ABC006EF5C1 /* SideNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73C5A6361CC12ABC006EF5C1 /* SideNavigationView.swift */; }; 73C8E4AF1C5A1D30005E0248 /* ProgressGeneralViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73C8E4AE1C5A1D30005E0248 /* ProgressGeneralViewController.swift */; }; 73D2BCE61C3C633200CE6C00 /* SideViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73D2BCE51C3C633200CE6C00 /* SideViewController.swift */; }; 73D2BCED1C3C6D6600CE6C00 /* SwiftyJSON.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 73D2BCEC1C3C6D6600CE6C00 /* SwiftyJSON.framework */; }; @@ -99,15 +121,13 @@ E0C7E3111B5BC12B00EB6389 /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0C7E3061B5BC12B00EB6389 /* Animator.swift */; }; E0C7E3171B5BC12B00EB6389 /* ImageSourceHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0C7E3091B5BC12B00EB6389 /* ImageSourceHelpers.swift */; }; E0C7E31D1B5BC12B00EB6389 /* UIImageExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0C7E30C1B5BC12B00EB6389 /* UIImageExtension.swift */; }; - E0CA1FC51BACA58D00FF6F8C /* TimerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0CA1FC41BACA58D00FF6F8C /* TimerController.swift */; }; E0CA1FC81BACA5A000FF6F8C /* PersistenceManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0CA1FC71BACA5A000FF6F8C /* PersistenceManager.swift */; }; E0F5872E1B5272C400540104 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0F5872C1B5272C400540104 /* AppDelegate.swift */; }; E0F587311B5272E200540104 /* Routine.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0F587301B5272E200540104 /* Routine.swift */; }; E0F587351B5272F400540104 /* ActionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0F587331B5272F400540104 /* ActionView.swift */; }; - E0F5873C1B52730000540104 /* SettingsController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0F587381B52730000540104 /* SettingsController.swift */; }; + E0F5873C1B52730000540104 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0F587381B52730000540104 /* SettingsViewController.swift */; }; E0F5873D1B52730000540104 /* TimePickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E0F587391B52730000540104 /* TimePickerController.swift */; }; - E0F587461B52730C00540104 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E0F587411B52730C00540104 /* Main.storyboard */; }; - E0F587471B52730C00540104 /* TimePicker.xib in Resources */ = {isa = PBXBuildFile; fileRef = E0F587431B52730C00540104 /* TimePicker.xib */; }; + E0F587471B52730C00540104 /* TimePickerModalView.xib in Resources */ = {isa = PBXBuildFile; fileRef = E0F587431B52730C00540104 /* TimePickerModalView.xib */; }; E0F5874A1B52731C00540104 /* finished.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = E0F587481B52731C00540104 /* finished.mp3 */; }; E0F5874B1B52731C00540104 /* Routine.json in Resources */ = {isa = PBXBuildFile; fileRef = E0F587491B52731C00540104 /* Routine.json */; }; E0F5877F1B52733100540104 /* advanced_tuck_front_lever_row.gif in Resources */ = {isa = PBXBuildFile; fileRef = E0F5874D1B52733100540104 /* advanced_tuck_front_lever_row.gif */; }; @@ -121,7 +141,6 @@ E0F587871B52733100540104 /* diamond_pushup.gif in Resources */ = {isa = PBXBuildFile; fileRef = E0F587551B52733100540104 /* diamond_pushup.gif */; }; E0F587881B52733100540104 /* floor_l_sit.gif in Resources */ = {isa = PBXBuildFile; fileRef = E0F587561B52733100540104 /* floor_l_sit.gif */; }; E0F587891B52733100540104 /* freestanding_handstand.gif in Resources */ = {isa = PBXBuildFile; fileRef = E0F587571B52733100540104 /* freestanding_handstand.gif */; }; - E0F5878A1B52733100540104 /* full_body_circles.gif in Resources */ = {isa = PBXBuildFile; fileRef = E0F587581B52733100540104 /* full_body_circles.gif */; }; E0F5878B1B52733100540104 /* hollow_hold.gif in Resources */ = {isa = PBXBuildFile; fileRef = E0F587591B52733100540104 /* hollow_hold.gif */; }; E0F5878C1B52733100540104 /* horizontal_row.gif in Resources */ = {isa = PBXBuildFile; fileRef = E0F5875A1B52733100540104 /* horizontal_row.gif */; }; E0F5878D1B52733100540104 /* incline_pushup.gif in Resources */ = {isa = PBXBuildFile; fileRef = E0F5875B1B52733100540104 /* incline_pushup.gif */; }; @@ -163,6 +182,16 @@ E0F587B41B52734900540104 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E0F587B31B52734900540104 /* Images.xcassets */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 73BADE701CC78356001ACEDC /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 2BD2CA7B1B458FFD00841AB7 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2BD2CA821B458FFD00841AB7; + remoteInfo = "Bodyweight Fitness"; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 73D2BCDB1C3C627200CE6C00 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; @@ -170,7 +199,6 @@ dstPath = ""; dstSubfolderSpec = 16; files = ( - 73BFEBBB1CBA8A5F00B9DDAE /* Material.framework.dSYM in CopyFiles */, 732BA0221C5ADC3100C1CDB5 /* PageMenuFramework.framework.dSYM in CopyFiles */, 7366D8E81C51AD9C00819790 /* SwiftCharts.framework.dSYM in CopyFiles */, 734B6FF91C4BE8CB00CFB6BD /* Realm.framework.dSYM in CopyFiles */, @@ -194,27 +222,27 @@ /* Begin PBXFileReference section */ 2BD2CA831B458FFD00841AB7 /* Bodyweight Fitness.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Bodyweight Fitness.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 46B020C26FAF7645B926FA26 /* CardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardView.swift; sourceTree = SOURCE_ROOT; }; + 46B020C26FAF7645B926FA26 /* CardView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardView.swift; sourceTree = ""; }; + 46B02AEDB4B0B259C2EAE1E8 /* WorkoutLogViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WorkoutLogViewController.swift; sourceTree = ""; }; 732BA01E1C5ADC1200C1CDB5 /* PageMenuFramework.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PageMenuFramework.framework; path = Carthage/Build/iOS/PageMenuFramework.framework; sourceTree = ""; }; 732BA0211C5ADC3100C1CDB5 /* PageMenuFramework.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = PageMenuFramework.framework.dSYM; path = Carthage/Build/iOS/PageMenuFramework.framework.dSYM; sourceTree = ""; }; - 732BA0231C5AE75900C1CDB5 /* ProgressPageViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ProgressPageViewController.xib; sourceTree = SOURCE_ROOT; }; - 732BA0251C5AE8EF00C1CDB5 /* CardViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CardViewCell.xib; sourceTree = SOURCE_ROOT; }; - 732BA0271C5AE8F900C1CDB5 /* SectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SectionViewCell.xib; sourceTree = SOURCE_ROOT; }; - 732BA0291C5B76DD00C1CDB5 /* CardViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CardViewCell.swift; sourceTree = SOURCE_ROOT; }; - 732BA02B1C5B76E500C1CDB5 /* SectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionViewCell.swift; sourceTree = SOURCE_ROOT; }; - 732BA02D1C5B7A8D00C1CDB5 /* ProgressGeneralViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ProgressGeneralViewController.xib; sourceTree = SOURCE_ROOT; }; - 732BA03C1C5BC9D400C1CDB5 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = SOURCE_ROOT; }; - 732BA0421C5EB9C300C1CDB5 /* CalendarCardViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalendarCardViewCell.swift; sourceTree = SOURCE_ROOT; }; - 732BA0441C5EB9CE00C1CDB5 /* CalendarCardViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CalendarCardViewCell.xib; sourceTree = SOURCE_ROOT; }; - 732BA0461C5EBB9900C1CDB5 /* CalendarSectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = CalendarSectionViewCell.xib; sourceTree = SOURCE_ROOT; }; - 732BA0481C5EBBA400C1CDB5 /* CalendarSectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalendarSectionViewCell.swift; sourceTree = SOURCE_ROOT; }; - 733876D41C4AB163006AABA7 /* LogWorkoutButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LogWorkoutButton.swift; sourceTree = SOURCE_ROOT; }; - 733876D91C4ABF88006AABA7 /* RoutineStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoutineStream.swift; sourceTree = SOURCE_ROOT; }; + 732BA0231C5AE75900C1CDB5 /* ProgressPageViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ProgressPageViewController.xib; sourceTree = ""; }; + 732BA0251C5AE8EF00C1CDB5 /* ProgressCardCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ProgressCardCell.xib; sourceTree = ""; }; + 732BA0271C5AE8F900C1CDB5 /* ProgressSectionCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ProgressSectionCell.xib; sourceTree = ""; }; + 732BA0291C5B76DD00C1CDB5 /* ProgressCardCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressCardCell.swift; sourceTree = ""; }; + 732BA02B1C5B76E500C1CDB5 /* ProgressSectionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressSectionCell.swift; sourceTree = ""; }; + 732BA02D1C5B7A8D00C1CDB5 /* ProgressGeneralViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ProgressGeneralViewController.xib; sourceTree = ""; }; + 732BA03C1C5BC9D400C1CDB5 /* LaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LaunchScreen.xib; sourceTree = ""; }; + 732BA0421C5EB9C300C1CDB5 /* WorkoutLogCardCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WorkoutLogCardCell.swift; sourceTree = ""; }; + 732BA0441C5EB9CE00C1CDB5 /* WorkoutLogCardCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WorkoutLogCardCell.xib; sourceTree = ""; }; + 732BA0461C5EBB9900C1CDB5 /* WorkoutLogSectionCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WorkoutLogSectionCell.xib; sourceTree = ""; }; + 732BA0481C5EBBA400C1CDB5 /* WorkoutLogSectionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WorkoutLogSectionCell.swift; sourceTree = ""; }; + 733876D41C4AB163006AABA7 /* LogWorkoutButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LogWorkoutButton.swift; sourceTree = ""; }; + 733876D91C4ABF88006AABA7 /* RoutineStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RoutineStream.swift; sourceTree = ""; }; 733876DC1C4AC829006AABA7 /* Runes.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = Runes.framework.dSYM; path = Carthage/Build/iOS/Runes.framework.dSYM; sourceTree = ""; }; 733876DD1C4AC829006AABA7 /* SwiftyJSON.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = SwiftyJSON.framework.dSYM; path = Carthage/Build/iOS/SwiftyJSON.framework.dSYM; sourceTree = ""; }; 7349F6A11C492729009DBE7B /* Runes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Runes.framework; path = Carthage/Build/iOS/Runes.framework; sourceTree = ""; }; - 734B6F3E1C4AE7E900CFB6BD /* LogWorkoutController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LogWorkoutController.swift; sourceTree = SOURCE_ROOT; }; - 734B6F411C4BAC6A00CFB6BD /* CalendarViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CalendarViewController.swift; sourceTree = SOURCE_ROOT; }; + 734B6F3E1C4AE7E900CFB6BD /* LogWorkoutController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LogWorkoutController.swift; sourceTree = ""; }; 734B6F961C4BB73D00CFB6BD /* CVAuxiliaryView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CVAuxiliaryView.swift; path = BodyweightFitness/Frameworks/Calendar/CVAuxiliaryView.swift; sourceTree = ""; }; 734B6F971C4BB73D00CFB6BD /* CVCalendarContentViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CVCalendarContentViewController.swift; path = BodyweightFitness/Frameworks/Calendar/CVCalendarContentViewController.swift; sourceTree = ""; }; 734B6F981C4BB73D00CFB6BD /* CVCalendarDayView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CVCalendarDayView.swift; path = BodyweightFitness/Frameworks/Calendar/CVCalendarDayView.swift; sourceTree = ""; }; @@ -246,111 +274,130 @@ 734B6FE81C4BE84600CFB6BD /* RealmSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = RealmSwift.framework; path = Carthage/Build/iOS/RealmSwift.framework; sourceTree = ""; }; 734B6FF71C4BE8CB00CFB6BD /* Realm.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = Realm.framework.dSYM; path = Carthage/Build/iOS/Realm.framework.dSYM; sourceTree = ""; }; 734B6FF81C4BE8CB00CFB6BD /* RealmSwift.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = RealmSwift.framework.dSYM; path = Carthage/Build/iOS/RealmSwift.framework.dSYM; sourceTree = ""; }; - 734B6FFE1C4BF46400CFB6BD /* RepositorySet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepositorySet.swift; sourceTree = SOURCE_ROOT; }; - 734B70011C4BF57600CFB6BD /* RepositoryStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepositoryStream.swift; sourceTree = SOURCE_ROOT; }; - 734B70041C4BF7C700CFB6BD /* RepositoryRoutine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepositoryRoutine.swift; sourceTree = SOURCE_ROOT; }; - 734B70071C4BF7DD00CFB6BD /* RepositoryCategory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepositoryCategory.swift; sourceTree = SOURCE_ROOT; }; - 734B700A1C4BF7E900CFB6BD /* RepositorySection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepositorySection.swift; sourceTree = SOURCE_ROOT; }; - 7366D8D01C4EE9CC00819790 /* ProgressViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressViewController.swift; sourceTree = SOURCE_ROOT; }; - 7366D8DC1C4EEFD500819790 /* ProgressPageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressPageViewController.swift; sourceTree = SOURCE_ROOT; }; - 7366D8E01C51810600819790 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = SOURCE_ROOT; }; + 734B6FFE1C4BF46400CFB6BD /* RepositorySet.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepositorySet.swift; sourceTree = ""; }; + 734B70011C4BF57600CFB6BD /* RepositoryStream.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepositoryStream.swift; sourceTree = ""; }; + 734B70041C4BF7C700CFB6BD /* RepositoryRoutine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepositoryRoutine.swift; sourceTree = ""; }; + 734B70071C4BF7DD00CFB6BD /* RepositoryCategory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepositoryCategory.swift; sourceTree = ""; }; + 734B700A1C4BF7E900CFB6BD /* RepositorySection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepositorySection.swift; sourceTree = ""; }; + 735BEA061CBD1E56003616C5 /* SideView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SideView.xib; sourceTree = ""; }; + 735BEA091CBD1F38003616C5 /* SideViewHeaderCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SideViewHeaderCell.xib; sourceTree = ""; }; + 735BEA0B1CBD1F5E003616C5 /* SideViewMenuCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SideViewMenuCell.xib; sourceTree = ""; }; + 7366D8D01C4EE9CC00819790 /* ProgressViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressViewController.swift; sourceTree = ""; }; + 7366D8DC1C4EEFD500819790 /* ProgressPageViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressPageViewController.swift; sourceTree = ""; }; + 7366D8E01C51810600819790 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; 7366D8E31C51AD5900819790 /* SwiftCharts.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftCharts.framework; path = Carthage/Build/iOS/SwiftCharts.framework; sourceTree = ""; }; 7366D8E61C51AD9600819790 /* SwiftCharts.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = SwiftCharts.framework.dSYM; path = Carthage/Build/iOS/SwiftCharts.framework.dSYM; sourceTree = ""; }; - 7366D8E91C52416C00819790 /* SupportDeveloperViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SupportDeveloperViewController.swift; sourceTree = SOURCE_ROOT; }; + 7366D8E91C52416C00819790 /* SupportDeveloperViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SupportDeveloperViewController.swift; sourceTree = ""; }; 7366D8EC1C52943D00819790 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; - 737F3C7F1CBE4A1800251EFE /* ring_wide_pushup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = ring_wide_pushup.gif; sourceTree = SOURCE_ROOT; }; - 73AA28E91CABE69200DEED79 /* DashboardViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardViewController.swift; sourceTree = SOURCE_ROOT; }; - 73AA28EC1CABE8F800DEED79 /* DashboardView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DashboardView.xib; sourceTree = SOURCE_ROOT; }; - 73AA28EE1CB7ABB500DEED79 /* DashboardSectionViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DashboardSectionViewCell.xib; sourceTree = SOURCE_ROOT; }; - 73AA28F01CB7ABC300DEED79 /* DashboardSectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardSectionViewCell.swift; sourceTree = SOURCE_ROOT; }; - 73AA28F21CB7ACC100DEED79 /* DashboardCategoryViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardCategoryViewCell.swift; sourceTree = SOURCE_ROOT; }; - 73AA28F41CB7ACCC00DEED79 /* DashboardCategoryViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DashboardCategoryViewCell.xib; sourceTree = SOURCE_ROOT; }; - 73AA28F61CB7ACD900DEED79 /* DashboardSingleItemViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DashboardSingleItemViewCell.xib; sourceTree = SOURCE_ROOT; }; - 73AA28F81CB7ACE300DEED79 /* DashboardDoubleItemViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DashboardDoubleItemViewCell.xib; sourceTree = SOURCE_ROOT; }; - 73AA28FA1CB7ACEB00DEED79 /* DashboardSingleItemViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardSingleItemViewCell.swift; sourceTree = SOURCE_ROOT; }; - 73AA28FC1CB7ACF500DEED79 /* DashboardDoubleItemViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardDoubleItemViewCell.swift; sourceTree = SOURCE_ROOT; }; - 73BFEBB71CBA889400B9DDAE /* Material.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Material.framework; path = Carthage/Build/iOS/Material.framework; sourceTree = ""; }; - 73BFEBB91CBA8A4700B9DDAE /* Material.framework.dSYM */ = {isa = PBXFileReference; lastKnownFileType = wrapper.dsym; name = Material.framework.dSYM; path = Carthage/Build/iOS/Material.framework.dSYM; sourceTree = ""; }; - 73BFEBBD1CBAC94300B9DDAE /* WeightUnitCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeightUnitCell.swift; sourceTree = SOURCE_ROOT; }; - 73BFEBBF1CBAE19A00B9DDAE /* DevelopedByCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DevelopedByCell.swift; sourceTree = SOURCE_ROOT; }; - 73BFEBC11CBAEDD800B9DDAE /* SnackBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnackBar.swift; sourceTree = ""; }; - 73BFEBC31CBBFA3900B9DDAE /* SupportDeveloperView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SupportDeveloperView.xib; sourceTree = SOURCE_ROOT; }; + 737F3C771CBD52AB00251EFE /* WorkoutLogView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WorkoutLogView.xib; sourceTree = ""; }; + 737F3C7F1CBE4A1800251EFE /* ring_wide_pushup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = ring_wide_pushup.gif; sourceTree = ""; }; + 73AA28E91CABE69200DEED79 /* DashboardViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardViewController.swift; sourceTree = ""; }; + 73AA28EC1CABE8F800DEED79 /* DashboardView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DashboardView.xib; sourceTree = ""; }; + 73AA28EE1CB7ABB500DEED79 /* DashboardSectionCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DashboardSectionCell.xib; sourceTree = ""; }; + 73AA28F01CB7ABC300DEED79 /* DashboardSectionCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardSectionCell.swift; sourceTree = ""; }; + 73AA28F21CB7ACC100DEED79 /* DashboardCategoryCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardCategoryCell.swift; sourceTree = ""; }; + 73AA28F41CB7ACCC00DEED79 /* DashboardCategoryCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DashboardCategoryCell.xib; sourceTree = ""; }; + 73AA28F61CB7ACD900DEED79 /* DashboardSingleItemCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DashboardSingleItemCell.xib; sourceTree = ""; }; + 73AA28F81CB7ACE300DEED79 /* DashboardDoubleItemCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DashboardDoubleItemCell.xib; sourceTree = ""; }; + 73AA28FA1CB7ACEB00DEED79 /* DashboardSingleItemCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardSingleItemCell.swift; sourceTree = ""; }; + 73AA28FC1CB7ACF500DEED79 /* DashboardDoubleItemCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DashboardDoubleItemCell.swift; sourceTree = ""; }; + 73BADE141CC3DC26001ACEDC /* RateMyApp.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RateMyApp.swift; path = BodyweightFitness/Vendor/RateMyApp.swift; sourceTree = ""; }; + 73BADE161CC3E2F9001ACEDC /* TimedView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TimedView.xib; sourceTree = ""; }; + 73BADE181CC3E347001ACEDC /* TimedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimedViewController.swift; sourceTree = ""; }; + 73BADE1A1CC3F956001ACEDC /* WeightedViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeightedViewController.swift; sourceTree = ""; }; + 73BADE1C1CC3F98D001ACEDC /* WeightedView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = WeightedView.xib; sourceTree = ""; }; + 73BADE241CC6EE94001ACEDC /* shoulder_rolls.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = shoulder_rolls.gif; sourceTree = ""; }; + 73BADE261CC6F19E001ACEDC /* band_pull_downs.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = band_pull_downs.gif; sourceTree = ""; }; + 73BADE281CC6F480001ACEDC /* band_chest_flies.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = band_chest_flies.gif; sourceTree = ""; }; + 73BADE6B1CC78356001ACEDC /* BodyweightFitnessTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = BodyweightFitnessTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 73BADE6D1CC78356001ACEDC /* BodyweightFitnessTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BodyweightFitnessTests.swift; sourceTree = ""; }; + 73BADE6F1CC78356001ACEDC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 73BADE7C1CC79648001ACEDC /* TestRoutine.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = TestRoutine.json; sourceTree = ""; }; + 73BF3BA81CBE643200E0258D /* SettingsView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsView.xib; sourceTree = ""; }; + 73BF3BAC1CBE6A5D00E0258D /* SettingsToggleCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsToggleCell.xib; sourceTree = ""; }; + 73BF3BAE1CBE6A7000E0258D /* SettingsActionCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsActionCell.xib; sourceTree = ""; }; + 73BF3BB01CBE6A8000E0258D /* SettingsTextCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsTextCell.xib; sourceTree = ""; }; + 73BF3BB21CBE819B00E0258D /* SettingsActionSubtitleCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsActionSubtitleCell.xib; sourceTree = ""; }; + 73BF3BB41CBEB08B00E0258D /* LogWorkoutModalView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = LogWorkoutModalView.xib; sourceTree = ""; }; + 73BF3BB81CBEFB0E00E0258D /* RootView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = RootView.xib; sourceTree = ""; }; + 73BF3BBA1CBEFB1E00E0258D /* RootViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RootViewController.swift; sourceTree = ""; }; + 73BF3BBE1CBF02D200E0258D /* Window.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = Window.xib; sourceTree = ""; }; + 73BF3BC01CBF05ED00E0258D /* SnackBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnackBar.swift; sourceTree = ""; }; + 73BF3BC61CBFF89D00E0258D /* NavigationView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NavigationView.xib; sourceTree = ""; }; + 73BF3BC81CBFFF0A00E0258D /* NavigationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NavigationViewController.swift; sourceTree = ""; }; + 73BFEBC31CBBFA3900B9DDAE /* SupportDeveloperView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SupportDeveloperView.xib; sourceTree = ""; }; 73BFEC041CBC2C9A00B9DDAE /* Fabric.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Fabric.framework; sourceTree = ""; }; 73BFEC051CBC2C9A00B9DDAE /* Crashlytics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Crashlytics.framework; sourceTree = ""; }; - 73C8E4AE1C5A1D30005E0248 /* ProgressGeneralViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressGeneralViewController.swift; sourceTree = SOURCE_ROOT; }; - 73D2BCE51C3C633200CE6C00 /* SideViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SideViewController.swift; sourceTree = SOURCE_ROOT; }; + 73C5A6361CC12ABC006EF5C1 /* SideNavigationView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SideNavigationView.swift; sourceTree = ""; }; + 73C8E4AE1C5A1D30005E0248 /* ProgressGeneralViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressGeneralViewController.swift; sourceTree = ""; }; + 73D2BCE51C3C633200CE6C00 /* SideViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SideViewController.swift; sourceTree = ""; }; 73D2BCEC1C3C6D6600CE6C00 /* SwiftyJSON.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyJSON.framework; path = Carthage/Build/iOS/SwiftyJSON.framework; sourceTree = ""; }; - 73FE1F5A1C4BF82A0047C97A /* RepositoryExercise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepositoryExercise.swift; sourceTree = SOURCE_ROOT; }; + 73FE1F5A1C4BF82A0047C97A /* RepositoryExercise.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RepositoryExercise.swift; sourceTree = ""; }; E0C7E3041B5BC12B00EB6389 /* AnimatableImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AnimatableImageView.swift; path = BodyweightFitness/Frameworks/AnimatableImageView.swift; sourceTree = ""; }; E0C7E3051B5BC12B00EB6389 /* AnimatedFrame.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AnimatedFrame.swift; path = BodyweightFitness/Frameworks/AnimatedFrame.swift; sourceTree = ""; }; E0C7E3061B5BC12B00EB6389 /* Animator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Animator.swift; path = BodyweightFitness/Frameworks/Animator.swift; sourceTree = ""; }; E0C7E3091B5BC12B00EB6389 /* ImageSourceHelpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageSourceHelpers.swift; path = BodyweightFitness/Frameworks/ImageSourceHelpers.swift; sourceTree = ""; }; E0C7E30C1B5BC12B00EB6389 /* UIImageExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = UIImageExtension.swift; path = BodyweightFitness/Frameworks/UIImageExtension.swift; sourceTree = ""; }; - E0CA1FC41BACA58D00FF6F8C /* TimerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TimerController.swift; path = BodyweightFitness/Controller/TimerController.swift; sourceTree = SOURCE_ROOT; }; - E0CA1FC71BACA5A000FF6F8C /* PersistenceManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PersistenceManager.swift; path = BodyweightFitness/Service/PersistenceManager.swift; sourceTree = SOURCE_ROOT; }; - E0F5870E1B52728E00540104 /* RoutineTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RoutineTests.swift; path = BodyweightFitnessTests/RoutineTests.swift; sourceTree = SOURCE_ROOT; }; - E0F587101B52729B00540104 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = BodyweightFitnessTests/Info.plist; sourceTree = SOURCE_ROOT; }; - E0F5872C1B5272C400540104 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = BodyweightFitness/AppDelegate.swift; sourceTree = SOURCE_ROOT; }; - E0F587301B5272E200540104 /* Routine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Routine.swift; path = BodyweightFitness/Model/Routine.swift; sourceTree = SOURCE_ROOT; }; - E0F587331B5272F400540104 /* ActionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ActionView.swift; path = BodyweightFitness/View/ActionView.swift; sourceTree = SOURCE_ROOT; }; - E0F587381B52730000540104 /* SettingsController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SettingsController.swift; path = BodyweightFitness/Controller/SettingsController.swift; sourceTree = SOURCE_ROOT; }; - E0F587391B52730000540104 /* TimePickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TimePickerController.swift; path = BodyweightFitness/Controller/TimePickerController.swift; sourceTree = SOURCE_ROOT; }; - E0F587421B52730C00540104 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = BodyweightFitness/Base.lproj/Main.storyboard; sourceTree = SOURCE_ROOT; }; - E0F587441B52730C00540104 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = BodyweightFitness/Base.lproj/TimePicker.xib; sourceTree = SOURCE_ROOT; }; - E0F587481B52731C00540104 /* finished.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; name = finished.mp3; path = BodyweightFitness/Resources/finished.mp3; sourceTree = SOURCE_ROOT; }; - E0F587491B52731C00540104 /* Routine.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = Routine.json; path = BodyweightFitness/Resources/Routine.json; sourceTree = SOURCE_ROOT; }; - E0F5874D1B52733100540104 /* advanced_tuck_front_lever_row.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = advanced_tuck_front_lever_row.gif; path = BodyweightFitness/Resources/Gifs/advanced_tuck_front_lever_row.gif; sourceTree = SOURCE_ROOT; }; - E0F5874E1B52733100540104 /* arch.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = arch.gif; path = BodyweightFitness/Resources/Gifs/arch.gif; sourceTree = SOURCE_ROOT; }; - E0F5874F1B52733100540104 /* assisted_squat.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = assisted_squat.gif; path = BodyweightFitness/Resources/Gifs/assisted_squat.gif; sourceTree = SOURCE_ROOT; }; - E0F587501B52733100540104 /* band_dislocates.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = band_dislocates.gif; path = BodyweightFitness/Resources/Gifs/band_dislocates.gif; sourceTree = SOURCE_ROOT; }; - E0F587511B52733100540104 /* bodyweight_squat.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = bodyweight_squat.gif; path = BodyweightFitness/Resources/Gifs/bodyweight_squat.gif; sourceTree = SOURCE_ROOT; }; - E0F587521B52733100540104 /* burpee.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = burpee.gif; path = BodyweightFitness/Resources/Gifs/burpee.gif; sourceTree = SOURCE_ROOT; }; - E0F587531B52733100540104 /* cat_camel.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = cat_camel.gif; path = BodyweightFitness/Resources/Gifs/cat_camel.gif; sourceTree = SOURCE_ROOT; }; - E0F587541B52733100540104 /* deep_stepup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = deep_stepup.gif; path = BodyweightFitness/Resources/Gifs/deep_stepup.gif; sourceTree = SOURCE_ROOT; }; - E0F587551B52733100540104 /* diamond_pushup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = diamond_pushup.gif; path = BodyweightFitness/Resources/Gifs/diamond_pushup.gif; sourceTree = SOURCE_ROOT; }; - E0F587561B52733100540104 /* floor_l_sit.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = floor_l_sit.gif; path = BodyweightFitness/Resources/Gifs/floor_l_sit.gif; sourceTree = SOURCE_ROOT; }; - E0F587571B52733100540104 /* freestanding_handstand.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = freestanding_handstand.gif; path = BodyweightFitness/Resources/Gifs/freestanding_handstand.gif; sourceTree = SOURCE_ROOT; }; - E0F587581B52733100540104 /* full_body_circles.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = full_body_circles.gif; path = BodyweightFitness/Resources/Gifs/full_body_circles.gif; sourceTree = SOURCE_ROOT; }; - E0F587591B52733100540104 /* hollow_hold.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = hollow_hold.gif; path = BodyweightFitness/Resources/Gifs/hollow_hold.gif; sourceTree = SOURCE_ROOT; }; - E0F5875A1B52733100540104 /* horizontal_row.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = horizontal_row.gif; path = BodyweightFitness/Resources/Gifs/horizontal_row.gif; sourceTree = SOURCE_ROOT; }; - E0F5875B1B52733100540104 /* incline_pushup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = incline_pushup.gif; path = BodyweightFitness/Resources/Gifs/incline_pushup.gif; sourceTree = SOURCE_ROOT; }; - E0F5875C1B52733100540104 /* incline_row.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = incline_row.gif; path = BodyweightFitness/Resources/Gifs/incline_row.gif; sourceTree = SOURCE_ROOT; }; - E0F5875D1B52733100540104 /* l_ring_dips.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = l_ring_dips.gif; path = BodyweightFitness/Resources/Gifs/l_ring_dips.gif; sourceTree = SOURCE_ROOT; }; - E0F5875E1B52733100540104 /* l_sit.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = l_sit.gif; path = BodyweightFitness/Resources/Gifs/l_sit.gif; sourceTree = SOURCE_ROOT; }; - E0F5875F1B52733100540104 /* leg_swings.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = leg_swings.gif; path = BodyweightFitness/Resources/Gifs/leg_swings.gif; sourceTree = SOURCE_ROOT; }; - E0F587601B52733100540104 /* lsit_pullup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = lsit_pullup.gif; path = BodyweightFitness/Resources/Gifs/lsit_pullup.gif; sourceTree = SOURCE_ROOT; }; - E0F587611B52733100540104 /* negative_pullup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = negative_pullup.gif; path = BodyweightFitness/Resources/Gifs/negative_pullup.gif; sourceTree = SOURCE_ROOT; }; - E0F587621B52733100540104 /* one_foot_l_sit.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = one_foot_l_sit.gif; path = BodyweightFitness/Resources/Gifs/one_foot_l_sit.gif; sourceTree = SOURCE_ROOT; }; - E0F587631B52733100540104 /* parallel_bar_dips.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = parallel_bar_dips.gif; path = BodyweightFitness/Resources/Gifs/parallel_bar_dips.gif; sourceTree = SOURCE_ROOT; }; - E0F587641B52733100540104 /* parallel_bar_hold.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = parallel_bar_hold.gif; path = BodyweightFitness/Resources/Gifs/parallel_bar_hold.gif; sourceTree = SOURCE_ROOT; }; - E0F587651B52733100540104 /* plank.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = plank.gif; path = BodyweightFitness/Resources/Gifs/plank.gif; sourceTree = SOURCE_ROOT; }; - E0F587661B52733100540104 /* pseudo_planche_pushup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = pseudo_planche_pushup.gif; path = BodyweightFitness/Resources/Gifs/pseudo_planche_pushup.gif; sourceTree = SOURCE_ROOT; }; - E0F587671B52733100540104 /* pseudo_planche.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = pseudo_planche.gif; path = BodyweightFitness/Resources/Gifs/pseudo_planche.gif; sourceTree = SOURCE_ROOT; }; - E0F587681B52733100540104 /* pullover.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = pullover.gif; path = BodyweightFitness/Resources/Gifs/pullover.gif; sourceTree = SOURCE_ROOT; }; - E0F587691B52733100540104 /* pullup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = pullup.gif; path = BodyweightFitness/Resources/Gifs/pullup.gif; sourceTree = SOURCE_ROOT; }; - E0F5876A1B52733100540104 /* pushup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = pushup.gif; path = BodyweightFitness/Resources/Gifs/pushup.gif; sourceTree = SOURCE_ROOT; }; - E0F5876B1B52733100540104 /* reverse_plank.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = reverse_plank.gif; path = BodyweightFitness/Resources/Gifs/reverse_plank.gif; sourceTree = SOURCE_ROOT; }; - E0F5876C1B52733100540104 /* ring_dips.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = ring_dips.gif; path = BodyweightFitness/Resources/Gifs/ring_dips.gif; sourceTree = SOURCE_ROOT; }; - E0F5876D1B52733100540104 /* ring_pushup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = ring_pushup.gif; path = BodyweightFitness/Resources/Gifs/ring_pushup.gif; sourceTree = SOURCE_ROOT; }; - E0F5876E1B52733100540104 /* ring_support.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = ring_support.gif; path = BodyweightFitness/Resources/Gifs/ring_support.gif; sourceTree = SOURCE_ROOT; }; - E0F5876F1B52733100540104 /* rings_turned_out_pushup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = rings_turned_out_pushup.gif; path = BodyweightFitness/Resources/Gifs/rings_turned_out_pushup.gif; sourceTree = SOURCE_ROOT; }; - E0F587701B52733100540104 /* rings_turned_out_support.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = rings_turned_out_support.gif; path = BodyweightFitness/Resources/Gifs/rings_turned_out_support.gif; sourceTree = SOURCE_ROOT; }; - E0F587711B52733100540104 /* scapular_shrugs.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = scapular_shrugs.gif; path = BodyweightFitness/Resources/Gifs/scapular_shrugs.gif; sourceTree = SOURCE_ROOT; }; - E0F587721B52733100540104 /* side_plank.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = side_plank.gif; path = BodyweightFitness/Resources/Gifs/side_plank.gif; sourceTree = SOURCE_ROOT; }; - E0F587731B52733100540104 /* squat_jumps.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = squat_jumps.gif; path = BodyweightFitness/Resources/Gifs/squat_jumps.gif; sourceTree = SOURCE_ROOT; }; - E0F587741B52733100540104 /* tuck_front_lever_row.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = tuck_front_lever_row.gif; path = BodyweightFitness/Resources/Gifs/tuck_front_lever_row.gif; sourceTree = SOURCE_ROOT; }; - E0F587751B52733100540104 /* tuck_front_lever.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = tuck_front_lever.gif; path = BodyweightFitness/Resources/Gifs/tuck_front_lever.gif; sourceTree = SOURCE_ROOT; }; - E0F587761B52733100540104 /* tuck_ice_cream_maker.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = tuck_ice_cream_maker.gif; path = BodyweightFitness/Resources/Gifs/tuck_ice_cream_maker.gif; sourceTree = SOURCE_ROOT; }; - E0F587771B52733100540104 /* tuck_l_sit.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = tuck_l_sit.gif; path = BodyweightFitness/Resources/Gifs/tuck_l_sit.gif; sourceTree = SOURCE_ROOT; }; - E0F587781B52733100540104 /* vertical_row.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = vertical_row.gif; path = BodyweightFitness/Resources/Gifs/vertical_row.gif; sourceTree = SOURCE_ROOT; }; - E0F587791B52733100540104 /* wall_extensions.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = wall_extensions.gif; path = BodyweightFitness/Resources/Gifs/wall_extensions.gif; sourceTree = SOURCE_ROOT; }; - E0F5877A1B52733100540104 /* wall_handstand.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = wall_handstand.gif; path = BodyweightFitness/Resources/Gifs/wall_handstand.gif; sourceTree = SOURCE_ROOT; }; - E0F5877B1B52733100540104 /* wall_plank.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = wall_plank.gif; path = BodyweightFitness/Resources/Gifs/wall_plank.gif; sourceTree = SOURCE_ROOT; }; - E0F5877C1B52733100540104 /* wall_pushup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = wall_pushup.gif; path = BodyweightFitness/Resources/Gifs/wall_pushup.gif; sourceTree = SOURCE_ROOT; }; - E0F5877D1B52733100540104 /* wide_row.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = wide_row.gif; path = BodyweightFitness/Resources/Gifs/wide_row.gif; sourceTree = SOURCE_ROOT; }; - E0F5877E1B52733100540104 /* wrist_progression.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; name = wrist_progression.gif; path = BodyweightFitness/Resources/Gifs/wrist_progression.gif; sourceTree = SOURCE_ROOT; }; - E0F587B11B52734000540104 /* Bodyweight Fitness.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "Bodyweight Fitness.plist"; path = "BodyweightFitness/Bodyweight Fitness.plist"; sourceTree = SOURCE_ROOT; }; - E0F587B31B52734900540104 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = BodyweightFitness/Images.xcassets; sourceTree = SOURCE_ROOT; }; + E0CA1FC71BACA5A000FF6F8C /* PersistenceManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PersistenceManager.swift; sourceTree = ""; }; + E0F5872C1B5272C400540104 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + E0F587301B5272E200540104 /* Routine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Routine.swift; sourceTree = ""; }; + E0F587331B5272F400540104 /* ActionView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionView.swift; sourceTree = ""; }; + E0F587381B52730000540104 /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; + E0F587391B52730000540104 /* TimePickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TimePickerController.swift; sourceTree = ""; }; + E0F587441B52730C00540104 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/TimePickerModalView.xib; sourceTree = ""; }; + E0F587481B52731C00540104 /* finished.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = finished.mp3; sourceTree = ""; }; + E0F587491B52731C00540104 /* Routine.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Routine.json; sourceTree = ""; }; + E0F5874D1B52733100540104 /* advanced_tuck_front_lever_row.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = advanced_tuck_front_lever_row.gif; sourceTree = ""; }; + E0F5874E1B52733100540104 /* arch.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = arch.gif; sourceTree = ""; }; + E0F5874F1B52733100540104 /* assisted_squat.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = assisted_squat.gif; sourceTree = ""; }; + E0F587501B52733100540104 /* band_dislocates.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = band_dislocates.gif; sourceTree = ""; }; + E0F587511B52733100540104 /* bodyweight_squat.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = bodyweight_squat.gif; sourceTree = ""; }; + E0F587521B52733100540104 /* burpee.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = burpee.gif; sourceTree = ""; }; + E0F587531B52733100540104 /* cat_camel.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = cat_camel.gif; sourceTree = ""; }; + E0F587541B52733100540104 /* deep_stepup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = deep_stepup.gif; sourceTree = ""; }; + E0F587551B52733100540104 /* diamond_pushup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = diamond_pushup.gif; sourceTree = ""; }; + E0F587561B52733100540104 /* floor_l_sit.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = floor_l_sit.gif; sourceTree = ""; }; + E0F587571B52733100540104 /* freestanding_handstand.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = freestanding_handstand.gif; sourceTree = ""; }; + E0F587591B52733100540104 /* hollow_hold.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = hollow_hold.gif; sourceTree = ""; }; + E0F5875A1B52733100540104 /* horizontal_row.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = horizontal_row.gif; sourceTree = ""; }; + E0F5875B1B52733100540104 /* incline_pushup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = incline_pushup.gif; sourceTree = ""; }; + E0F5875C1B52733100540104 /* incline_row.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = incline_row.gif; sourceTree = ""; }; + E0F5875D1B52733100540104 /* l_ring_dips.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = l_ring_dips.gif; sourceTree = ""; }; + E0F5875E1B52733100540104 /* l_sit.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = l_sit.gif; sourceTree = ""; }; + E0F5875F1B52733100540104 /* leg_swings.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = leg_swings.gif; sourceTree = ""; }; + E0F587601B52733100540104 /* lsit_pullup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = lsit_pullup.gif; sourceTree = ""; }; + E0F587611B52733100540104 /* negative_pullup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = negative_pullup.gif; sourceTree = ""; }; + E0F587621B52733100540104 /* one_foot_l_sit.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = one_foot_l_sit.gif; sourceTree = ""; }; + E0F587631B52733100540104 /* parallel_bar_dips.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = parallel_bar_dips.gif; sourceTree = ""; }; + E0F587641B52733100540104 /* parallel_bar_hold.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = parallel_bar_hold.gif; sourceTree = ""; }; + E0F587651B52733100540104 /* plank.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = plank.gif; sourceTree = ""; }; + E0F587661B52733100540104 /* pseudo_planche_pushup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = pseudo_planche_pushup.gif; sourceTree = ""; }; + E0F587671B52733100540104 /* pseudo_planche.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = pseudo_planche.gif; sourceTree = ""; }; + E0F587681B52733100540104 /* pullover.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = pullover.gif; sourceTree = ""; }; + E0F587691B52733100540104 /* pullup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = pullup.gif; sourceTree = ""; }; + E0F5876A1B52733100540104 /* pushup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = pushup.gif; sourceTree = ""; }; + E0F5876B1B52733100540104 /* reverse_plank.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = reverse_plank.gif; sourceTree = ""; }; + E0F5876C1B52733100540104 /* ring_dips.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = ring_dips.gif; sourceTree = ""; }; + E0F5876D1B52733100540104 /* ring_pushup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = ring_pushup.gif; sourceTree = ""; }; + E0F5876E1B52733100540104 /* ring_support.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = ring_support.gif; sourceTree = ""; }; + E0F5876F1B52733100540104 /* rings_turned_out_pushup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = rings_turned_out_pushup.gif; sourceTree = ""; }; + E0F587701B52733100540104 /* rings_turned_out_support.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = rings_turned_out_support.gif; sourceTree = ""; }; + E0F587711B52733100540104 /* scapular_shrugs.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = scapular_shrugs.gif; sourceTree = ""; }; + E0F587721B52733100540104 /* side_plank.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = side_plank.gif; sourceTree = ""; }; + E0F587731B52733100540104 /* squat_jumps.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = squat_jumps.gif; sourceTree = ""; }; + E0F587741B52733100540104 /* tuck_front_lever_row.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = tuck_front_lever_row.gif; sourceTree = ""; }; + E0F587751B52733100540104 /* tuck_front_lever.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = tuck_front_lever.gif; sourceTree = ""; }; + E0F587761B52733100540104 /* tuck_ice_cream_maker.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = tuck_ice_cream_maker.gif; sourceTree = ""; }; + E0F587771B52733100540104 /* tuck_l_sit.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = tuck_l_sit.gif; sourceTree = ""; }; + E0F587781B52733100540104 /* vertical_row.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = vertical_row.gif; sourceTree = ""; }; + E0F587791B52733100540104 /* wall_extensions.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = wall_extensions.gif; sourceTree = ""; }; + E0F5877A1B52733100540104 /* wall_handstand.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = wall_handstand.gif; sourceTree = ""; }; + E0F5877B1B52733100540104 /* wall_plank.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = wall_plank.gif; sourceTree = ""; }; + E0F5877C1B52733100540104 /* wall_pushup.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = wall_pushup.gif; sourceTree = ""; }; + E0F5877D1B52733100540104 /* wide_row.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = wide_row.gif; sourceTree = ""; }; + E0F5877E1B52733100540104 /* wrist_progression.gif */ = {isa = PBXFileReference; lastKnownFileType = image.gif; path = wrist_progression.gif; sourceTree = ""; }; + E0F587B11B52734000540104 /* Bodyweight Fitness.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Bodyweight Fitness.plist"; sourceTree = ""; }; + E0F587B31B52734900540104 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -358,7 +405,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 73BFEBB81CBA889400B9DDAE /* Material.framework in Frameworks */, 732BA01F1C5ADC1200C1CDB5 /* PageMenuFramework.framework in Frameworks */, 7366D8E51C51AD6C00819790 /* SwiftCharts.framework in Frameworks */, 73D2BCED1C3C6D6600CE6C00 /* SwiftyJSON.framework in Frameworks */, @@ -371,6 +417,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 73BADE681CC78356001ACEDC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -378,8 +431,8 @@ isa = PBXGroup; children = ( 2BD2CA851B458FFD00841AB7 /* BodyweightFitness */, + 73BADE6C1CC78356001ACEDC /* BodyweightFitnessTests */, E00242FB1B4F1CFD0003A230 /* Frameworks */, - 2BD2CA9E1B458FFE00841AB7 /* BodyweightFitnessTests */, 2BD2CA841B458FFD00841AB7 /* Products */, ); sourceTree = ""; @@ -388,6 +441,7 @@ isa = PBXGroup; children = ( 2BD2CA831B458FFD00841AB7 /* Bodyweight Fitness.app */, + 73BADE6B1CC78356001ACEDC /* BodyweightFitnessTests.xctest */, ); name = Products; sourceTree = ""; @@ -395,63 +449,17 @@ 2BD2CA851B458FFD00841AB7 /* BodyweightFitness */ = { isa = PBXGroup; children = ( + E0F587B11B52734000540104 /* Bodyweight Fitness.plist */, E0F5872C1B5272C400540104 /* AppDelegate.swift */, 7366D8E01C51810600819790 /* Extensions.swift */, - E078934D1B472CCD001195AC /* Model */, - E078934C1B472CAF001195AC /* View */, 73BA31BC1CB83A9B001784F7 /* Controller */, - 73AA28EB1CABE8E000DEED79 /* UI */, - E02BF7B01B45E2EB00D5CE52 /* RefactorController */, - E0C7E3241B5BC65000EB6389 /* Service */, - E00242CB1B4B0E370003A230 /* Layout */, + E078934D1B472CCD001195AC /* Model */, E08139041B5270EE00390A73 /* Resources */, - 2BD2CA861B458FFD00841AB7 /* Supporting Files */, - ); - name = BodyweightFitness; - path = TabsTest; - sourceTree = ""; - }; - 2BD2CA861B458FFD00841AB7 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - E0F587B11B52734000540104 /* Bodyweight Fitness.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 2BD2CA9E1B458FFE00841AB7 /* BodyweightFitnessTests */ = { - isa = PBXGroup; - children = ( - E0F5870E1B52728E00540104 /* RoutineTests.swift */, - E0F587101B52729B00540104 /* Info.plist */, - ); - name = BodyweightFitnessTests; - path = TabsTestTests; - sourceTree = ""; - }; - 732BA0411C5EB6A600C1CDB5 /* Cell */ = { - isa = PBXGroup; - children = ( - 732BA0421C5EB9C300C1CDB5 /* CalendarCardViewCell.swift */, - 732BA0441C5EB9CE00C1CDB5 /* CalendarCardViewCell.xib */, - 732BA0481C5EBBA400C1CDB5 /* CalendarSectionViewCell.swift */, - 732BA0461C5EBB9900C1CDB5 /* CalendarSectionViewCell.xib */, - 732BA0291C5B76DD00C1CDB5 /* CardViewCell.swift */, - 732BA0251C5AE8EF00C1CDB5 /* CardViewCell.xib */, - 732BA02B1C5B76E500C1CDB5 /* SectionViewCell.swift */, - 732BA0271C5AE8F900C1CDB5 /* SectionViewCell.xib */, - 73AA28F21CB7ACC100DEED79 /* DashboardCategoryViewCell.swift */, - 73AA28F41CB7ACCC00DEED79 /* DashboardCategoryViewCell.xib */, - 73AA28F01CB7ABC300DEED79 /* DashboardSectionViewCell.swift */, - 73AA28EE1CB7ABB500DEED79 /* DashboardSectionViewCell.xib */, - 73AA28FA1CB7ACEB00DEED79 /* DashboardSingleItemViewCell.swift */, - 73AA28F61CB7ACD900DEED79 /* DashboardSingleItemViewCell.xib */, - 73AA28FC1CB7ACF500DEED79 /* DashboardDoubleItemViewCell.swift */, - 73AA28F81CB7ACE300DEED79 /* DashboardDoubleItemViewCell.xib */, - 73BFEBBD1CBAC94300B9DDAE /* WeightUnitCell.swift */, - 73BFEBBF1CBAE19A00B9DDAE /* DevelopedByCell.swift */, + 73AA28EB1CABE8E000DEED79 /* UI */, + E078934C1B472CAF001195AC /* View */, + E0F587B31B52734900540104 /* Images.xcassets */, ); - name = Cell; + path = BodyweightFitness; sourceTree = ""; }; 734B6F951C4BB72C00CFB6BD /* Calendar */ = { @@ -488,38 +496,111 @@ name = Calendar; sourceTree = ""; }; - 734B6FFD1C4BF45900CFB6BD /* Repository */ = { + 735BEA081CBD1F29003616C5 /* Cell */ = { isa = PBXGroup; children = ( - 734B70041C4BF7C700CFB6BD /* RepositoryRoutine.swift */, - 734B70071C4BF7DD00CFB6BD /* RepositoryCategory.swift */, - 734B700A1C4BF7E900CFB6BD /* RepositorySection.swift */, - 73FE1F5A1C4BF82A0047C97A /* RepositoryExercise.swift */, - 734B6FFE1C4BF46400CFB6BD /* RepositorySet.swift */, + 73AA28F41CB7ACCC00DEED79 /* DashboardCategoryCell.xib */, + 73AA28F81CB7ACE300DEED79 /* DashboardDoubleItemCell.xib */, + 73AA28EE1CB7ABB500DEED79 /* DashboardSectionCell.xib */, + 73AA28F61CB7ACD900DEED79 /* DashboardSingleItemCell.xib */, + 732BA0251C5AE8EF00C1CDB5 /* ProgressCardCell.xib */, + 732BA0271C5AE8F900C1CDB5 /* ProgressSectionCell.xib */, + 73BF3BAE1CBE6A7000E0258D /* SettingsActionCell.xib */, + 73BF3BB21CBE819B00E0258D /* SettingsActionSubtitleCell.xib */, + 73BF3BB01CBE6A8000E0258D /* SettingsTextCell.xib */, + 73BF3BAC1CBE6A5D00E0258D /* SettingsToggleCell.xib */, + 735BEA091CBD1F38003616C5 /* SideViewHeaderCell.xib */, + 735BEA0B1CBD1F5E003616C5 /* SideViewMenuCell.xib */, + 732BA0441C5EB9CE00C1CDB5 /* WorkoutLogCardCell.xib */, + 732BA0461C5EBB9900C1CDB5 /* WorkoutLogSectionCell.xib */, + ); + path = Cell; + sourceTree = ""; + }; + 737F3C7E1CBD593200251EFE /* Modal */ = { + isa = PBXGroup; + children = ( + 73BF3BB41CBEB08B00E0258D /* LogWorkoutModalView.xib */, + E0F587431B52730C00540104 /* TimePickerModalView.xib */, ); - name = Repository; + path = Modal; sourceTree = ""; }; 73AA28EB1CABE8E000DEED79 /* UI */ = { isa = PBXGroup; children = ( + 735BEA081CBD1F29003616C5 /* Cell */, + 737F3C7E1CBD593200251EFE /* Modal */, + 73AA28EC1CABE8F800DEED79 /* DashboardView.xib */, + 732BA03C1C5BC9D400C1CDB5 /* LaunchScreen.xib */, 732BA02D1C5B7A8D00C1CDB5 /* ProgressGeneralViewController.xib */, 732BA0231C5AE75900C1CDB5 /* ProgressPageViewController.xib */, - 73AA28EC1CABE8F800DEED79 /* DashboardView.xib */, + 73BF3BC61CBFF89D00E0258D /* NavigationView.xib */, + 73BF3BB81CBEFB0E00E0258D /* RootView.xib */, + 73BADE161CC3E2F9001ACEDC /* TimedView.xib */, + 73BADE1C1CC3F98D001ACEDC /* WeightedView.xib */, + 73BF3BA81CBE643200E0258D /* SettingsView.xib */, + 735BEA061CBD1E56003616C5 /* SideView.xib */, 73BFEBC31CBBFA3900B9DDAE /* SupportDeveloperView.xib */, + 73BF3BBE1CBF02D200E0258D /* Window.xib */, + 737F3C771CBD52AB00251EFE /* WorkoutLogView.xib */, ); - name = UI; + path = UI; sourceTree = ""; }; 73BA31BC1CB83A9B001784F7 /* Controller */ = { isa = PBXGroup; children = ( + 73BF3BB71CBEF0CC00E0258D /* Cell */, + 73BF3BB61CBEB0C100E0258D /* Modal */, + E0C7E3241B5BC65000EB6389 /* Service */, + 73AA28E91CABE69200DEED79 /* DashboardViewController.swift */, 73C8E4AE1C5A1D30005E0248 /* ProgressGeneralViewController.swift */, 7366D8DC1C4EEFD500819790 /* ProgressPageViewController.swift */, - 73AA28E91CABE69200DEED79 /* DashboardViewController.swift */, + 7366D8D01C4EE9CC00819790 /* ProgressViewController.swift */, + 73BF3BC81CBFFF0A00E0258D /* NavigationViewController.swift */, + 73BF3BBA1CBEFB1E00E0258D /* RootViewController.swift */, + 73BADE181CC3E347001ACEDC /* TimedViewController.swift */, + 73BADE1A1CC3F956001ACEDC /* WeightedViewController.swift */, + E0F587381B52730000540104 /* SettingsViewController.swift */, + 73D2BCE51C3C633200CE6C00 /* SideViewController.swift */, 7366D8E91C52416C00819790 /* SupportDeveloperViewController.swift */, + 46B02AEDB4B0B259C2EAE1E8 /* WorkoutLogViewController.swift */, ); - name = Controller; + path = Controller; + sourceTree = ""; + }; + 73BADE6C1CC78356001ACEDC /* BodyweightFitnessTests */ = { + isa = PBXGroup; + children = ( + 73BADE6D1CC78356001ACEDC /* BodyweightFitnessTests.swift */, + 73BADE6F1CC78356001ACEDC /* Info.plist */, + ); + path = BodyweightFitnessTests; + sourceTree = ""; + }; + 73BF3BB61CBEB0C100E0258D /* Modal */ = { + isa = PBXGroup; + children = ( + 734B6F3E1C4AE7E900CFB6BD /* LogWorkoutController.swift */, + E0F587391B52730000540104 /* TimePickerController.swift */, + ); + path = Modal; + sourceTree = ""; + }; + 73BF3BB71CBEF0CC00E0258D /* Cell */ = { + isa = PBXGroup; + children = ( + 73AA28F21CB7ACC100DEED79 /* DashboardCategoryCell.swift */, + 73AA28FC1CB7ACF500DEED79 /* DashboardDoubleItemCell.swift */, + 73AA28F01CB7ABC300DEED79 /* DashboardSectionCell.swift */, + 73AA28FA1CB7ACEB00DEED79 /* DashboardSingleItemCell.swift */, + 732BA0291C5B76DD00C1CDB5 /* ProgressCardCell.swift */, + 732BA02B1C5B76E500C1CDB5 /* ProgressSectionCell.swift */, + 732BA0421C5EB9C300C1CDB5 /* WorkoutLogCardCell.swift */, + 732BA0481C5EBBA400C1CDB5 /* WorkoutLogSectionCell.swift */, + ); + path = Cell; sourceTree = ""; }; 73BFEBBC1CBA8B4900B9DDAE /* dSYM */ = { @@ -529,29 +610,17 @@ 732BA0211C5ADC3100C1CDB5 /* PageMenuFramework.framework.dSYM */, 7366D8E61C51AD9600819790 /* SwiftCharts.framework.dSYM */, 733876DD1C4AC829006AABA7 /* SwiftyJSON.framework.dSYM */, - 73BFEBB91CBA8A4700B9DDAE /* Material.framework.dSYM */, 734B6FF71C4BE8CB00CFB6BD /* Realm.framework.dSYM */, 734B6FF81C4BE8CB00CFB6BD /* RealmSwift.framework.dSYM */, ); name = dSYM; sourceTree = ""; }; - E00242CB1B4B0E370003A230 /* Layout */ = { - isa = PBXGroup; - children = ( - E0F587411B52730C00540104 /* Main.storyboard */, - E0F587431B52730C00540104 /* TimePicker.xib */, - 732BA03C1C5BC9D400C1CDB5 /* LaunchScreen.xib */, - ); - name = Layout; - sourceTree = ""; - }; E00242FB1B4F1CFD0003A230 /* Frameworks */ = { isa = PBXGroup; children = ( 73BFEC041CBC2C9A00B9DDAE /* Fabric.framework */, 73BFEC051CBC2C9A00B9DDAE /* Crashlytics.framework */, - 73BFEBB71CBA889400B9DDAE /* Material.framework */, 732BA01E1C5ADC1200C1CDB5 /* PageMenuFramework.framework */, 7366D8EC1C52943D00819790 /* StoreKit.framework */, 7366D8E31C51AD5900819790 /* SwiftCharts.framework */, @@ -562,54 +631,45 @@ 73BFEBBC1CBA8B4900B9DDAE /* dSYM */, 734B6F951C4BB72C00CFB6BD /* Calendar */, E0C7E3201B5BC60600EB6389 /* Gifu */, - 73BFEBC11CBAEDD800B9DDAE /* SnackBar.swift */, + 73BADE141CC3DC26001ACEDC /* RateMyApp.swift */, ); name = Frameworks; sourceTree = ""; }; - E02BF7B01B45E2EB00D5CE52 /* RefactorController */ = { - isa = PBXGroup; - children = ( - 732BA0411C5EB6A600C1CDB5 /* Cell */, - E0F587391B52730000540104 /* TimePickerController.swift */, - 734B6F3E1C4AE7E900CFB6BD /* LogWorkoutController.swift */, - 734B6F411C4BAC6A00CFB6BD /* CalendarViewController.swift */, - 7366D8D01C4EE9CC00819790 /* ProgressViewController.swift */, - 73D2BCE51C3C633200CE6C00 /* SideViewController.swift */, - E0CA1FC41BACA58D00FF6F8C /* TimerController.swift */, - E0F587381B52730000540104 /* SettingsController.swift */, - ); - name = RefactorController; - sourceTree = ""; - }; E078934C1B472CAF001195AC /* View */ = { isa = PBXGroup; children = ( + 73C5A6361CC12ABC006EF5C1 /* SideNavigationView.swift */, E0F587331B5272F400540104 /* ActionView.swift */, - 733876D41C4AB163006AABA7 /* LogWorkoutButton.swift */, 46B020C26FAF7645B926FA26 /* CardView.swift */, + 733876D41C4AB163006AABA7 /* LogWorkoutButton.swift */, + 73BF3BC01CBF05ED00E0258D /* SnackBar.swift */, ); - name = View; + path = View; sourceTree = ""; }; E078934D1B472CCD001195AC /* Model */ = { isa = PBXGroup; children = ( - 734B6FFD1C4BF45900CFB6BD /* Repository */, + 734B70071C4BF7DD00CFB6BD /* RepositoryCategory.swift */, + 73FE1F5A1C4BF82A0047C97A /* RepositoryExercise.swift */, + 734B70041C4BF7C700CFB6BD /* RepositoryRoutine.swift */, + 734B700A1C4BF7E900CFB6BD /* RepositorySection.swift */, + 734B6FFE1C4BF46400CFB6BD /* RepositorySet.swift */, E0F587301B5272E200540104 /* Routine.swift */, ); - name = Model; + path = Model; sourceTree = ""; }; E08139041B5270EE00390A73 /* Resources */ = { isa = PBXGroup; children = ( E0F5874C1B52732500540104 /* Gifs */, - E0F587B31B52734900540104 /* Images.xcassets */, - E0F587481B52731C00540104 /* finished.mp3 */, E0F587491B52731C00540104 /* Routine.json */, + 73BADE7C1CC79648001ACEDC /* TestRoutine.json */, + E0F587481B52731C00540104 /* finished.mp3 */, ); - name = Resources; + path = Resources; sourceTree = ""; }; E0C7E3201B5BC60600EB6389 /* Gifu */ = { @@ -628,15 +688,18 @@ isa = PBXGroup; children = ( E0CA1FC71BACA5A000FF6F8C /* PersistenceManager.swift */, - 733876D91C4ABF88006AABA7 /* RoutineStream.swift */, 734B70011C4BF57600CFB6BD /* RepositoryStream.swift */, + 733876D91C4ABF88006AABA7 /* RoutineStream.swift */, ); - name = Service; + path = Service; sourceTree = ""; }; E0F5874C1B52732500540104 /* Gifs */ = { isa = PBXGroup; children = ( + 73BADE281CC6F480001ACEDC /* band_chest_flies.gif */, + 73BADE261CC6F19E001ACEDC /* band_pull_downs.gif */, + 73BADE241CC6EE94001ACEDC /* shoulder_rolls.gif */, E0F5874D1B52733100540104 /* advanced_tuck_front_lever_row.gif */, E0F5874E1B52733100540104 /* arch.gif */, E0F5874F1B52733100540104 /* assisted_squat.gif */, @@ -648,7 +711,6 @@ E0F587551B52733100540104 /* diamond_pushup.gif */, E0F587561B52733100540104 /* floor_l_sit.gif */, E0F587571B52733100540104 /* freestanding_handstand.gif */, - E0F587581B52733100540104 /* full_body_circles.gif */, E0F587591B52733100540104 /* hollow_hold.gif */, E0F5875A1B52733100540104 /* horizontal_row.gif */, E0F5875B1B52733100540104 /* incline_pushup.gif */, @@ -662,23 +724,23 @@ E0F587631B52733100540104 /* parallel_bar_dips.gif */, E0F587641B52733100540104 /* parallel_bar_hold.gif */, E0F587651B52733100540104 /* plank.gif */, - E0F587661B52733100540104 /* pseudo_planche_pushup.gif */, E0F587671B52733100540104 /* pseudo_planche.gif */, + E0F587661B52733100540104 /* pseudo_planche_pushup.gif */, E0F587681B52733100540104 /* pullover.gif */, E0F587691B52733100540104 /* pullup.gif */, E0F5876A1B52733100540104 /* pushup.gif */, E0F5876B1B52733100540104 /* reverse_plank.gif */, E0F5876C1B52733100540104 /* ring_dips.gif */, E0F5876D1B52733100540104 /* ring_pushup.gif */, - 737F3C7F1CBE4A1800251EFE /* ring_wide_pushup.gif */, E0F5876E1B52733100540104 /* ring_support.gif */, + 737F3C7F1CBE4A1800251EFE /* ring_wide_pushup.gif */, E0F5876F1B52733100540104 /* rings_turned_out_pushup.gif */, E0F587701B52733100540104 /* rings_turned_out_support.gif */, E0F587711B52733100540104 /* scapular_shrugs.gif */, E0F587721B52733100540104 /* side_plank.gif */, E0F587731B52733100540104 /* squat_jumps.gif */, - E0F587741B52733100540104 /* tuck_front_lever_row.gif */, E0F587751B52733100540104 /* tuck_front_lever.gif */, + E0F587741B52733100540104 /* tuck_front_lever_row.gif */, E0F587761B52733100540104 /* tuck_ice_cream_maker.gif */, E0F587771B52733100540104 /* tuck_l_sit.gif */, E0F587781B52733100540104 /* vertical_row.gif */, @@ -689,7 +751,7 @@ E0F5877D1B52733100540104 /* wide_row.gif */, E0F5877E1B52733100540104 /* wrist_progression.gif */, ); - name = Gifs; + path = Gifs; sourceTree = ""; }; /* End PBXGroup section */ @@ -716,25 +778,47 @@ productReference = 2BD2CA831B458FFD00841AB7 /* Bodyweight Fitness.app */; productType = "com.apple.product-type.application"; }; + 73BADE6A1CC78356001ACEDC /* BodyweightFitnessTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 73BADE721CC78356001ACEDC /* Build configuration list for PBXNativeTarget "BodyweightFitnessTests" */; + buildPhases = ( + 73BADE671CC78356001ACEDC /* Sources */, + 73BADE681CC78356001ACEDC /* Frameworks */, + 73BADE691CC78356001ACEDC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 73BADE711CC78356001ACEDC /* PBXTargetDependency */, + ); + name = BodyweightFitnessTests; + productName = BodyweightFitnessTests; + productReference = 73BADE6B1CC78356001ACEDC /* BodyweightFitnessTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 2BD2CA7B1B458FFD00841AB7 /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftUpdateCheck = 0700; + LastSwiftUpdateCheck = 0730; LastUpgradeCheck = 0720; ORGANIZATIONNAME = "Damian Mazurkiewicz"; TargetAttributes = { 2BD2CA821B458FFD00841AB7 = { CreatedOnToolsVersion = 6.2; - DevelopmentTeam = 32UU4L8Z8S; + DevelopmentTeam = F2262GQ94A; SystemCapabilities = { com.apple.InAppPurchase = { enabled = 1; }; }; }; + 73BADE6A1CC78356001ACEDC = { + CreatedOnToolsVersion = 7.3; + TestTargetID = 2BD2CA821B458FFD00841AB7; + }; }; }; buildConfigurationList = 2BD2CA7E1B458FFD00841AB7 /* Build configuration list for PBXProject "BodyweightFitness" */; @@ -751,6 +835,7 @@ projectRoot = ""; targets = ( 2BD2CA821B458FFD00841AB7 /* Bodyweight Fitness */, + 73BADE6A1CC78356001ACEDC /* BodyweightFitnessTests */, ); }; /* End PBXProject section */ @@ -762,23 +847,25 @@ files = ( E0F587991B52733100540104 /* pseudo_planche.gif in Resources */, E0F587A31B52733100540104 /* scapular_shrugs.gif in Resources */, + 73BADE271CC6F19E001ACEDC /* band_pull_downs.gif in Resources */, 73AA28ED1CABE8F800DEED79 /* DashboardView.xib in Resources */, E0F587911B52733100540104 /* leg_swings.gif in Resources */, E0F587821B52733100540104 /* band_dislocates.gif in Resources */, - 73AA28EF1CB7ABB500DEED79 /* DashboardSectionViewCell.xib in Resources */, - 732BA0471C5EBB9900C1CDB5 /* CalendarSectionViewCell.xib in Resources */, + 73AA28EF1CB7ABB500DEED79 /* DashboardSectionCell.xib in Resources */, + 732BA0471C5EBB9900C1CDB5 /* WorkoutLogSectionCell.xib in Resources */, E0F587841B52733100540104 /* burpee.gif in Resources */, 732BA02E1C5B7A8D00C1CDB5 /* ProgressGeneralViewController.xib in Resources */, E0F587AA1B52733100540104 /* vertical_row.gif in Resources */, E0F587AB1B52733100540104 /* wall_extensions.gif in Resources */, E0F587A11B52733100540104 /* rings_turned_out_pushup.gif in Resources */, - 732BA0281C5AE8F900C1CDB5 /* SectionViewCell.xib in Resources */, + 732BA0281C5AE8F900C1CDB5 /* ProgressSectionCell.xib in Resources */, E0F587971B52733100540104 /* plank.gif in Resources */, - 73AA28F71CB7ACD900DEED79 /* DashboardSingleItemViewCell.xib in Resources */, - 73AA28F91CB7ACE300DEED79 /* DashboardDoubleItemViewCell.xib in Resources */, + 73AA28F71CB7ACD900DEED79 /* DashboardSingleItemCell.xib in Resources */, + 73AA28F91CB7ACE300DEED79 /* DashboardDoubleItemCell.xib in Resources */, E0F5874B1B52731C00540104 /* Routine.json in Resources */, + 73BADE1D1CC3F98D001ACEDC /* WeightedView.xib in Resources */, + 73BF3BB11CBE6A8000E0258D /* SettingsTextCell.xib in Resources */, E0F587901B52733100540104 /* l_sit.gif in Resources */, - E0F587461B52730C00540104 /* Main.storyboard in Resources */, E0F587941B52733100540104 /* one_foot_l_sit.gif in Resources */, E0F5879A1B52733100540104 /* pullover.gif in Resources */, E0F587861B52733100540104 /* deep_stepup.gif in Resources */, @@ -788,16 +875,21 @@ E0F587951B52733100540104 /* parallel_bar_dips.gif in Resources */, E0F587A81B52733100540104 /* tuck_ice_cream_maker.gif in Resources */, E0F587A01B52733100540104 /* ring_support.gif in Resources */, - 73AA28F51CB7ACCC00DEED79 /* DashboardCategoryViewCell.xib in Resources */, + 73AA28F51CB7ACCC00DEED79 /* DashboardCategoryCell.xib in Resources */, E0F5878C1B52733100540104 /* horizontal_row.gif in Resources */, E0F587871B52733100540104 /* diamond_pushup.gif in Resources */, E0F587A71B52733100540104 /* tuck_front_lever.gif in Resources */, - E0F5878A1B52733100540104 /* full_body_circles.gif in Resources */, + 73BADE171CC3E2F9001ACEDC /* TimedView.xib in Resources */, + 73BF3BB51CBEB08B00E0258D /* LogWorkoutModalView.xib in Resources */, E0F5879C1B52733100540104 /* pushup.gif in Resources */, + 73BF3BC71CBFF89D00E0258D /* NavigationView.xib in Resources */, E0F587931B52733100540104 /* negative_pullup.gif in Resources */, + 73BF3BAF1CBE6A7000E0258D /* SettingsActionCell.xib in Resources */, E0F587B01B52733100540104 /* wrist_progression.gif in Resources */, E0F587A91B52733100540104 /* tuck_l_sit.gif in Resources */, + 737F3C781CBD52AB00251EFE /* WorkoutLogView.xib in Resources */, E0F587811B52733100540104 /* assisted_squat.gif in Resources */, + 73BADE291CC6F480001ACEDC /* band_chest_flies.gif in Resources */, 737F3C801CBE4A1800251EFE /* ring_wide_pushup.gif in Resources */, E0F5878E1B52733100540104 /* incline_row.gif in Resources */, E0F587891B52733100540104 /* freestanding_handstand.gif in Resources */, @@ -805,30 +897,47 @@ E0F587AE1B52733100540104 /* wall_pushup.gif in Resources */, E0F587A21B52733100540104 /* rings_turned_out_support.gif in Resources */, E0F5874A1B52731C00540104 /* finished.mp3 in Resources */, - E0F587471B52730C00540104 /* TimePicker.xib in Resources */, + E0F587471B52730C00540104 /* TimePickerModalView.xib in Resources */, E0F587881B52733100540104 /* floor_l_sit.gif in Resources */, - 732BA0261C5AE8EF00C1CDB5 /* CardViewCell.xib in Resources */, + 73BF3BB31CBE819B00E0258D /* SettingsActionSubtitleCell.xib in Resources */, + 73BF3BBF1CBF02D200E0258D /* Window.xib in Resources */, + 732BA0261C5AE8EF00C1CDB5 /* ProgressCardCell.xib in Resources */, E0F5878B1B52733100540104 /* hollow_hold.gif in Resources */, E0F587A41B52733100540104 /* side_plank.gif in Resources */, E0F5879D1B52733100540104 /* reverse_plank.gif in Resources */, + 735BEA071CBD1E56003616C5 /* SideView.xib in Resources */, E0F587851B52733100540104 /* cat_camel.gif in Resources */, E0F5879F1B52733100540104 /* ring_pushup.gif in Resources */, 73BFEBC41CBBFA3900B9DDAE /* SupportDeveloperView.xib in Resources */, + 73BF3BB91CBEFB0E00E0258D /* RootView.xib in Resources */, E0F5878D1B52733100540104 /* incline_pushup.gif in Resources */, E0F587981B52733100540104 /* pseudo_planche_pushup.gif in Resources */, E0F587961B52733100540104 /* parallel_bar_hold.gif in Resources */, E0F587801B52733100540104 /* arch.gif in Resources */, + 73BF3BA91CBE643200E0258D /* SettingsView.xib in Resources */, E0F587A51B52733100540104 /* squat_jumps.gif in Resources */, 732BA0241C5AE75900C1CDB5 /* ProgressPageViewController.xib in Resources */, E0F587921B52733100540104 /* lsit_pullup.gif in Resources */, E0F5878F1B52733100540104 /* l_ring_dips.gif in Resources */, + 735BEA0A1CBD1F38003616C5 /* SideViewHeaderCell.xib in Resources */, E0F587A61B52733100540104 /* tuck_front_lever_row.gif in Resources */, E0F587AC1B52733100540104 /* wall_handstand.gif in Resources */, + 735BEA0C1CBD1F5E003616C5 /* SideViewMenuCell.xib in Resources */, + 73BADE7D1CC79648001ACEDC /* TestRoutine.json in Resources */, 732BA03D1C5BC9D400C1CDB5 /* LaunchScreen.xib in Resources */, E0F587B41B52734900540104 /* Images.xcassets in Resources */, + 73BADE251CC6EE94001ACEDC /* shoulder_rolls.gif in Resources */, E0F5877F1B52733100540104 /* advanced_tuck_front_lever_row.gif in Resources */, E0F587831B52733100540104 /* bodyweight_squat.gif in Resources */, - 732BA0451C5EB9CE00C1CDB5 /* CalendarCardViewCell.xib in Resources */, + 732BA0451C5EB9CE00C1CDB5 /* WorkoutLogCardCell.xib in Resources */, + 73BF3BAD1CBE6A5D00E0258D /* SettingsToggleCell.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 73BADE691CC78356001ACEDC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( ); runOnlyForDeploymentPostprocessing = 0; }; @@ -854,7 +963,6 @@ files = ( ); inputPaths = ( - "$(SRCROOT)/Carthage/Build/iOS/Material.framework", "$(SRCROOT)/Carthage/Build/iOS/SwiftyJSON.framework", "$(SRCROOT)/Carthage/Build/iOS/Runes.framework", "$(SRCROOT)/Carthage/Build/iOS/RealmSwift.framework", @@ -890,8 +998,7 @@ E0C7E30D1B5BC12B00EB6389 /* AnimatableImageView.swift in Sources */, 734B6FD31C4BB73D00CFB6BD /* CVCalendarWeekContentViewController.swift in Sources */, 7366D8E11C51810600819790 /* Extensions.swift in Sources */, - 73BFEBC01CBAE19A00B9DDAE /* DevelopedByCell.swift in Sources */, - 732BA02C1C5B76E500C1CDB5 /* SectionViewCell.swift in Sources */, + 732BA02C1C5B76E500C1CDB5 /* ProgressSectionCell.swift in Sources */, E0C7E30F1B5BC12B00EB6389 /* AnimatedFrame.swift in Sources */, 734B70021C4BF57600CFB6BD /* RepositoryStream.swift in Sources */, 734B6FC91C4BB73D00CFB6BD /* CVCalendarViewAnimatorDelegate.swift in Sources */, @@ -899,32 +1006,32 @@ 7366D8DD1C4EEFD500819790 /* ProgressPageViewController.swift in Sources */, 734B6FD11C4BB73D00CFB6BD /* CVCalendarViewPresentationMode.swift in Sources */, 733876D51C4AB163006AABA7 /* LogWorkoutButton.swift in Sources */, - 73AA28FD1CB7ACF500DEED79 /* DashboardDoubleItemViewCell.swift in Sources */, + 73AA28FD1CB7ACF500DEED79 /* DashboardDoubleItemCell.swift in Sources */, 734B6FFF1C4BF46400CFB6BD /* RepositorySet.swift in Sources */, 734B6FB71C4BB73D00CFB6BD /* CVCalendarDayViewControlCoordinator.swift in Sources */, - 73BFEBBE1CBAC94300B9DDAE /* WeightUnitCell.swift in Sources */, - 732BA0491C5EBBA400C1CDB5 /* CalendarSectionViewCell.swift in Sources */, + 732BA0491C5EBBA400C1CDB5 /* WorkoutLogSectionCell.swift in Sources */, E0CA1FC81BACA5A000FF6F8C /* PersistenceManager.swift in Sources */, - 73AA28F31CB7ACC100DEED79 /* DashboardCategoryViewCell.swift in Sources */, + 73AA28F31CB7ACC100DEED79 /* DashboardCategoryCell.swift in Sources */, E0F587311B5272E200540104 /* Routine.swift in Sources */, 7366D8EA1C52416C00819790 /* SupportDeveloperViewController.swift in Sources */, 734B6FD91C4BB73D00CFB6BD /* CVDate.swift in Sources */, 734B6FBD1C4BB73D00CFB6BD /* CVCalendarMenuViewDelegate.swift in Sources */, - E0F5873C1B52730000540104 /* SettingsController.swift in Sources */, - 734B6F421C4BAC6A00CFB6BD /* CalendarViewController.swift in Sources */, + E0F5873C1B52730000540104 /* SettingsViewController.swift in Sources */, 734B6FD71C4BB73D00CFB6BD /* CVCalendarWeekView.swift in Sources */, E0C7E3111B5BC12B00EB6389 /* Animator.swift in Sources */, 734B6FCD1C4BB73D00CFB6BD /* CVCalendarViewAppearanceDelegate.swift in Sources */, - 732BA0431C5EB9C300C1CDB5 /* CalendarCardViewCell.swift in Sources */, + 73BADE151CC3DC26001ACEDC /* RateMyApp.swift in Sources */, + 732BA0431C5EB9C300C1CDB5 /* WorkoutLogCardCell.swift in Sources */, 734B6FB91C4BB73D00CFB6BD /* CVCalendarManager.swift in Sources */, - 73BFEBC21CBAEDD800B9DDAE /* SnackBar.swift in Sources */, + 73BADE1B1CC3F956001ACEDC /* WeightedViewController.swift in Sources */, 734B6FE51C4BB73D00CFB6BD /* CVWeekdaySymbolType.swift in Sources */, 733876DA1C4ABF88006AABA7 /* RoutineStream.swift in Sources */, + 73BF3BBB1CBEFB1E00E0258D /* RootViewController.swift in Sources */, 73D2BCE61C3C633200CE6C00 /* SideViewController.swift in Sources */, 734B6FB31C4BB73D00CFB6BD /* CVCalendarContentViewController.swift in Sources */, - 732BA02A1C5B76DD00C1CDB5 /* CardViewCell.swift in Sources */, + 732BA02A1C5B76DD00C1CDB5 /* ProgressCardCell.swift in Sources */, E0F5872E1B5272C400540104 /* AppDelegate.swift in Sources */, - 73AA28FB1CB7ACEB00DEED79 /* DashboardSingleItemViewCell.swift in Sources */, + 73AA28FB1CB7ACEB00DEED79 /* DashboardSingleItemCell.swift in Sources */, 734B6FD51C4BB73D00CFB6BD /* CVCalendarWeekday.swift in Sources */, 73AA28EA1CABE69200DEED79 /* DashboardViewController.swift in Sources */, 734B6FDD1C4BB73D00CFB6BD /* CVScrollDirection.swift in Sources */, @@ -932,37 +1039,50 @@ 734B6FDF1C4BB73D00CFB6BD /* CVSelectionType.swift in Sources */, 734B6FC11C4BB73D00CFB6BD /* CVCalendarMonthView.swift in Sources */, 734B6FC31C4BB73D00CFB6BD /* CVCalendarTouchController.swift in Sources */, + 73BF3BC91CBFFF0A00E0258D /* NavigationViewController.swift in Sources */, 734B6FCB1C4BB73D00CFB6BD /* CVCalendarViewAppearance.swift in Sources */, - 73AA28F11CB7ABC300DEED79 /* DashboardSectionViewCell.swift in Sources */, - E0CA1FC51BACA58D00FF6F8C /* TimerController.swift in Sources */, + 73AA28F11CB7ABC300DEED79 /* DashboardSectionCell.swift in Sources */, 734B6FC71C4BB73D00CFB6BD /* CVCalendarViewAnimator.swift in Sources */, 73FE1F5B1C4BF82A0047C97A /* RepositoryExercise.swift in Sources */, + 73C5A6371CC12ABC006EF5C1 /* SideNavigationView.swift in Sources */, + 73BF3BC11CBF05ED00E0258D /* SnackBar.swift in Sources */, 73C8E4AF1C5A1D30005E0248 /* ProgressGeneralViewController.swift in Sources */, 734B6FC51C4BB73D00CFB6BD /* CVCalendarView.swift in Sources */, 734B6FE31C4BB73D00CFB6BD /* CVShape.swift in Sources */, 734B6FB51C4BB73D00CFB6BD /* CVCalendarDayView.swift in Sources */, + 73BADE191CC3E347001ACEDC /* TimedViewController.swift in Sources */, 734B6F3F1C4AE7E900CFB6BD /* LogWorkoutController.swift in Sources */, 46B02780EEC08B16FB384A4F /* CardView.swift in Sources */, + 46B021B6A56C2000CA08000B /* WorkoutLogViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 73BADE671CC78356001ACEDC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 73BADE6E1CC78356001ACEDC /* BodyweightFitnessTests.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXVariantGroup section */ - E0F587411B52730C00540104 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - E0F587421B52730C00540104 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; +/* Begin PBXTargetDependency section */ + 73BADE711CC78356001ACEDC /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 2BD2CA821B458FFD00841AB7 /* Bodyweight Fitness */; + targetProxy = 73BADE701CC78356001ACEDC /* PBXContainerItemProxy */; }; - E0F587431B52730C00540104 /* TimePicker.xib */ = { +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + E0F587431B52730C00540104 /* TimePickerModalView.xib */ = { isa = PBXVariantGroup; children = ( E0F587441B52730C00540104 /* Base */, ); - name = TimePicker.xib; + name = TimePickerModalView.xib; + path = .; sourceTree = ""; }; /* End PBXVariantGroup section */ @@ -1039,6 +1159,7 @@ ENABLE_BITCODE = NO; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; @@ -1063,6 +1184,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Developer: Damian Mazurkiewicz (2HYG5VX9N6)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer: Damian Mazurkiewicz (2HYG5VX9N6)"; + DEFINES_MODULE = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", @@ -1088,6 +1210,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_IDENTITY = "iPhone Distribution: Damian Mazurkiewicz (32UU4L8Z8S)"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: Damian Mazurkiewicz (32UU4L8Z8S)"; + DEFINES_MODULE = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)", @@ -1105,6 +1228,43 @@ }; name = Release; }; + 73BADE731CC78356001ACEDC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ANALYZER_NONNULL = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEBUG_INFORMATION_FORMAT = dwarf; + FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/Carthage/Build/iOS"; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = BodyweightFitnessTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.mazur.BodyweightFitnessTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + "SWIFT_INCLUDE_PATHS[arch=*]" = "$(inherited)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Bodyweight Fitness.app/Bodyweight Fitness"; + }; + name = Debug; + }; + 73BADE741CC78356001ACEDC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CLANG_ANALYZER_NONNULL = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + FRAMEWORK_SEARCH_PATHS = "$(SRCROOT)/Carthage/Build/iOS"; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = BodyweightFitnessTests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 9.3; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = io.mazur.BodyweightFitnessTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Bodyweight Fitness.app/Bodyweight Fitness"; + }; + name = Release; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -1126,6 +1286,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 73BADE721CC78356001ACEDC /* Build configuration list for PBXNativeTarget "BodyweightFitnessTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 73BADE731CC78356001ACEDC /* Debug */, + 73BADE741CC78356001ACEDC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; /* End XCConfigurationList section */ }; rootObject = 2BD2CA7B1B458FFD00841AB7 /* Project object */; diff --git a/BodyweightFitness/AppDelegate.swift b/BodyweightFitness/AppDelegate.swift index 8de96dd..72fb887 100755 --- a/BodyweightFitness/AppDelegate.swift +++ b/BodyweightFitness/AppDelegate.swift @@ -1,5 +1,4 @@ import UIKit -import Material import CoreData import Fabric import Crashlytics @@ -7,39 +6,42 @@ import Crashlytics @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - var mask: CALayer? var sideNavigationViewController: SideNavigationController? - var sideViewController: UIViewController? - var mainViewController: UIViewController? - var calendarViewController: UIViewController? - var supportDeveloperViewController: UIViewController = UINavigationController(rootViewController: SupportDeveloperViewController()) - var settingsViewController: UIViewController? + let sideViewController: UIViewController = + SideViewController() + + let rootViewController: UINavigationController = + UINavigationController(rootViewController: RootViewController()) + + let workoutLogViewController = + UINavigationController(rootViewController: WorkoutLogViewController()) + + let supportDeveloperViewController = + UINavigationController(rootViewController: SupportDeveloperViewController()) + + let settingsViewController = + UINavigationController(rootViewController: SettingsViewController()) func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { Fabric.with([Crashlytics.self]) - - UITabBar.appearance().backgroundColor = UIColor(red:0, green:0.59, blue:0.53, alpha:1) - UITabBar.appearance().tintColor = UIColor(red:0, green:0.59, blue:0.53, alpha:1) - - let storyboard = UIStoryboard(name: "Main", bundle: nil) - sideViewController = storyboard.instantiateViewControllerWithIdentifier("SideViewController") as! SideViewController - mainViewController = storyboard.instantiateViewControllerWithIdentifier("MainViewController") - calendarViewController = storyboard.instantiateViewControllerWithIdentifier("CalendarNavigationController") - settingsViewController = storyboard.instantiateViewControllerWithIdentifier("NavigationSettingsController") + self.migrateSchemaIfNeeded() + self.setDefaultSettings() - sideNavigationViewController = SideNavigationController( - rootViewController: mainViewController!, - leftViewController: sideViewController! + self.sideNavigationViewController = SideNavigationController( + rootViewController: self.rootViewController, + leftViewController: self.sideViewController ) - - sideNavigationViewController?.setLeftViewWidth(260, hidden: true, animated: false) - - window = UIWindow(frame: UIScreen.mainScreen().bounds) - window?.rootViewController = sideNavigationViewController! - window?.makeKeyAndVisible() + + self.sideNavigationViewController?.setLeftViewWidth(260, hidden: true, animated: false) + + self.window = UIWindow(frame: UIScreen.mainScreen().bounds) + self.window?.tintColor = UIColor.primaryDark() + self.window?.backgroundColor = UIColor.primary() + self.window?.rootViewController = self.sideNavigationViewController! + self.window?.makeKeyAndVisible() return true } @@ -51,5 +53,72 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func applicationDidBecomeActive(application: UIApplication) { UIApplication.sharedApplication().idleTimerDisabled = true } + + func setDefaultSettings() { + let defaults = NSUserDefaults.standardUserDefaults() + + if(defaults.objectForKey("playAudioWhenTimerStops") == nil) { + defaults.setBool(true, forKey: "playAudioWhenTimerStops") + } + } + + func migrateSchemaIfNeeded() { + if (RepositoryStream.sharedInstance.repositoryRoutineForTodayExists()) { + let routine = RoutineStream.sharedInstance.routine + let currentSchema = RepositoryStream.sharedInstance.getRepositoryRoutineForToday() + + let (shouldRemoveCurrentSchema, newSchema) = migrateSchemaIfNeeded(routine, currentSchema: currentSchema) + + if shouldRemoveCurrentSchema { + let realm = RepositoryStream.sharedInstance.getRealm() + + try! realm.write { + realm.add(newSchema, update: false) + realm.delete(currentSchema) + } + } + } + } + + func migrateSchemaIfNeeded(routine: Routine, currentSchema: RepositoryRoutine) -> (Bool, RepositoryRoutine) { + if (!isValidSchema(routine, currentSchema: currentSchema)) { + let newSchema = RepositoryStream.sharedInstance.buildRoutine(routine) + + newSchema.startTime = currentSchema.startTime + newSchema.lastUpdatedTime = currentSchema.lastUpdatedTime + + for exercise in newSchema.exercises { + if let currentExercise = currentSchema.exercises.filter({ + $0.exerciseId == exercise.exerciseId + }).first { + exercise.sets.removeAll() + + for set in currentExercise.sets { + exercise.sets.append(set) + } + } + } + + return (true, newSchema) + } + + return (false, currentSchema) + } + + func isValidSchema(routine: Routine, currentSchema: RepositoryRoutine) -> Bool { + for exercise in routine.exercises { + if let exercise = exercise as? Exercise { + let containsExercise = currentSchema.exercises.contains({ + $0.exerciseId == exercise.exerciseId + }) + + if (!containsExercise) { + return false + } + } + } + + return true + } } diff --git a/BodyweightFitness/Base.lproj/Main.storyboard b/BodyweightFitness/Base.lproj/Main.storyboard deleted file mode 100755 index c81706e..0000000 --- a/BodyweightFitness/Base.lproj/Main.storyboard +++ /dev/null @@ -1,1039 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/BodyweightFitness/Bodyweight Fitness.plist b/BodyweightFitness/Bodyweight Fitness.plist index 1f05ad0..8e285b7 100755 --- a/BodyweightFitness/Bodyweight Fitness.plist +++ b/BodyweightFitness/Bodyweight Fitness.plist @@ -15,11 +15,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.1.1 + 1.2.0 CFBundleSignature ???? CFBundleVersion - 112 + 121 Fabric APIKey @@ -36,14 +36,18 @@ LSRequiresIPhoneOS + NSMainNibFile + Window UILaunchStoryboardName LaunchScreen - UIMainStoryboardFile - Main UIRequiredDeviceCapabilities armv7 + UIRequiresFullScreen + + UIStatusBarStyle + UIStatusBarStyleDefault UISupportedInterfaceOrientations UIInterfaceOrientationPortrait @@ -51,9 +55,8 @@ UISupportedInterfaceOrientations~ipad UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight + UIViewControllerBasedStatusBarAppearance + diff --git a/DashboardCategoryViewCell.swift b/BodyweightFitness/Controller/Cell/DashboardCategoryCell.swift similarity index 84% rename from DashboardCategoryViewCell.swift rename to BodyweightFitness/Controller/Cell/DashboardCategoryCell.swift index 6ea4000..1a59040 100644 --- a/DashboardCategoryViewCell.swift +++ b/BodyweightFitness/Controller/Cell/DashboardCategoryCell.swift @@ -1,6 +1,6 @@ import UIKit -class DashboardCategoryViewCell: UITableViewCell { +class DashboardCategoryCell: UITableViewCell { @IBOutlet weak var title: UILabel! override func awakeFromNib() { diff --git a/DashboardDoubleItemViewCell.swift b/BodyweightFitness/Controller/Cell/DashboardDoubleItemCell.swift similarity index 91% rename from DashboardDoubleItemViewCell.swift rename to BodyweightFitness/Controller/Cell/DashboardDoubleItemCell.swift index 8a72892..05aae65 100644 --- a/DashboardDoubleItemViewCell.swift +++ b/BodyweightFitness/Controller/Cell/DashboardDoubleItemCell.swift @@ -1,6 +1,6 @@ import UIKit -class DashboardDoubleItemViewCell: UITableViewCell { +class DashboardDoubleItemCell: UITableViewCell { @IBOutlet weak var leftTitle: UILabel! @IBOutlet weak var rightTitle: UILabel! @@ -59,8 +59,8 @@ class DashboardDoubleItemViewCell: UITableViewCell { self.rightView.layer.cornerRadius = self.rightView.frame.size.width / 2 self.rightView.clipsToBounds = true - self.leftView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(DashboardDoubleItemViewCell.onLeftClick(_:)))) - self.rightView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(DashboardDoubleItemViewCell.onRightClick(_:)))) + self.leftView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(DashboardDoubleItemCell.onLeftClick(_:)))) + self.rightView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(DashboardDoubleItemCell.onRightClick(_:)))) } override func setSelected(selected: Bool, animated: Bool) { diff --git a/DashboardSectionViewCell.swift b/BodyweightFitness/Controller/Cell/DashboardSectionCell.swift similarity index 86% rename from DashboardSectionViewCell.swift rename to BodyweightFitness/Controller/Cell/DashboardSectionCell.swift index 6b6c46a..d0e980b 100644 --- a/DashboardSectionViewCell.swift +++ b/BodyweightFitness/Controller/Cell/DashboardSectionCell.swift @@ -1,6 +1,6 @@ import UIKit -class DashboardSectionViewCell: UITableViewCell { +class DashboardSectionCell: UITableViewCell { @IBOutlet weak var title: UILabel! @IBOutlet weak var desc: UILabel! diff --git a/DashboardSingleItemViewCell.swift b/BodyweightFitness/Controller/Cell/DashboardSingleItemCell.swift similarity index 90% rename from DashboardSingleItemViewCell.swift rename to BodyweightFitness/Controller/Cell/DashboardSingleItemCell.swift index 01b9b3f..b5f1f18 100644 --- a/DashboardSingleItemViewCell.swift +++ b/BodyweightFitness/Controller/Cell/DashboardSingleItemCell.swift @@ -1,6 +1,6 @@ import UIKit -class DashboardSingleItemViewCell: UITableViewCell { +class DashboardSingleItemCell: UITableViewCell { @IBOutlet weak var title: UILabel! @IBOutlet weak var view: ActionView! @IBOutlet weak var button: UIButton! @@ -31,7 +31,7 @@ class DashboardSingleItemViewCell: UITableViewCell { self.view.layer.cornerRadius = self.view.frame.size.width / 2 self.view.clipsToBounds = true - self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(DashboardSingleItemViewCell.onClick(_:)))) + self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(DashboardSingleItemCell.onClick(_:)))) } override func setSelected(selected: Bool, animated: Bool) { diff --git a/BodyweightFitness/Controller/Cell/ProgressCardCell.swift b/BodyweightFitness/Controller/Cell/ProgressCardCell.swift new file mode 100644 index 0000000..ac4d867 --- /dev/null +++ b/BodyweightFitness/Controller/Cell/ProgressCardCell.swift @@ -0,0 +1,31 @@ +import UIKit + +class ProgressCardCell: UITableViewCell { + var parentController: UIViewController? + + @IBOutlet weak var title: UILabel! + @IBOutlet weak var subtitle: UILabel! + + var current: RepositoryExercise? + + override func awakeFromNib() { + super.awakeFromNib() + } + + override func setSelected(selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + } + + @IBAction func onClickFullReport(sender: AnyObject) { + let logWorkoutController = LogWorkoutController() + + logWorkoutController.parentController = self.parentController?.sideNavigationController + logWorkoutController.setRepositoryRoutine(current!, repositoryRoutine: RepositoryStream.sharedInstance.getRepositoryRoutineForToday()) + + logWorkoutController.modalTransitionStyle = .CoverVertical + logWorkoutController.modalPresentationStyle = .Custom + + self.parentController?.sideNavigationController?.dim(.In, alpha: 0.5, speed: 0.5) + self.parentController?.sideNavigationController?.presentViewController(logWorkoutController, animated: true, completion: nil) + } +} diff --git a/SectionViewCell.swift b/BodyweightFitness/Controller/Cell/ProgressSectionCell.swift similarity index 87% rename from SectionViewCell.swift rename to BodyweightFitness/Controller/Cell/ProgressSectionCell.swift index 79de0f8..0182940 100644 --- a/SectionViewCell.swift +++ b/BodyweightFitness/Controller/Cell/ProgressSectionCell.swift @@ -1,6 +1,6 @@ import UIKit -class SectionViewCell: UITableViewCell { +class ProgressSectionCell: UITableViewCell { var parentController: UIViewController? @IBOutlet weak var title: UILabel! diff --git a/CalendarCardViewCell.swift b/BodyweightFitness/Controller/Cell/WorkoutLogCardCell.swift similarity index 89% rename from CalendarCardViewCell.swift rename to BodyweightFitness/Controller/Cell/WorkoutLogCardCell.swift index 94752fd..ad63ea8 100644 --- a/CalendarCardViewCell.swift +++ b/BodyweightFitness/Controller/Cell/WorkoutLogCardCell.swift @@ -9,7 +9,7 @@ func getWeightUnit() -> String { } } -class CalendarCardViewCell: UITableViewCell, MFMailComposeViewControllerDelegate { +class WorkoutLogCardCell: UITableViewCell, MFMailComposeViewControllerDelegate { @IBOutlet weak var title: UILabel! @IBOutlet weak var subtitle: UILabel! @@ -31,8 +31,7 @@ class CalendarCardViewCell: UITableViewCell, MFMailComposeViewControllerDelegate self.parentController?.navigationItem.backBarButtonItem = backItem - let progressViewController = self.parentController?.storyboard!.instantiateViewControllerWithIdentifier("ProgressViewController") as! ProgressViewController - + let progressViewController = ProgressViewController() progressViewController.setRoutine(self.date!, repositoryRoutine: self.repositoryRoutine!) self.parentController?.showViewController(progressViewController, sender: nil) @@ -88,7 +87,7 @@ class CalendarCardViewCell: UITableViewCell, MFMailComposeViewControllerDelegate content.appendString("\n\nWorkout on \(helper.getStartTime(true)).") content.appendString("\nLast Updated at \(helper.getLastUpdatedTime())") - content.appendString("\nWorkout length: --") + content.appendString("\nWorkout length: \(helper.getWorkoutLength())") content.appendString("\n\n\(routine.title)\n\(routine.subtitle)") @@ -105,11 +104,17 @@ class CalendarCardViewCell: UITableViewCell, MFMailComposeViewControllerDelegate content.appendString("\nSet \(index)") if (set.isTimed) { - content.appendString("\nMinutes: \(minutes)") - content.appendString("\nSeconds: \(seconds)") + if minutes > 0 { + content.appendString(", Minutes: \(minutes)") + } + + content.appendString(", Seconds: \(seconds)") } else { - content.appendString("\nReps: \(set.reps)") - content.appendString("\nWeight: \(set.weight) \(weightUnit)") + content.appendString(", Reps: \(set.reps)") + + if set.weight > 0 { + content.appendString(", Weight: \(set.weight) \(weightUnit)") + } } index += 1 @@ -155,7 +160,7 @@ class CalendarCardViewCell: UITableViewCell, MFMailComposeViewControllerDelegate realm.delete(self.repositoryRoutine!) } - if let parent = self.parentController as? CalendarViewController { + if let parent = self.parentController as? WorkoutLogViewController { if let date = self.date { parent.showOrHideCardViewForDate(date) } diff --git a/CalendarSectionViewCell.swift b/BodyweightFitness/Controller/Cell/WorkoutLogSectionCell.swift similarity index 73% rename from CalendarSectionViewCell.swift rename to BodyweightFitness/Controller/Cell/WorkoutLogSectionCell.swift index 64a39ff..b44ee08 100644 --- a/CalendarSectionViewCell.swift +++ b/BodyweightFitness/Controller/Cell/WorkoutLogSectionCell.swift @@ -1,8 +1,6 @@ import UIKit -class CalendarSectionViewCell: UITableViewCell { - var parentController: UIViewController? - +class WorkoutLogSectionCell: UITableViewCell { @IBOutlet weak var title: UILabel! override func awakeFromNib() { diff --git a/DashboardViewController.swift b/BodyweightFitness/Controller/DashboardViewController.swift similarity index 86% rename from DashboardViewController.swift rename to BodyweightFitness/Controller/DashboardViewController.swift index 01ef432..cb4f029 100644 --- a/DashboardViewController.swift +++ b/BodyweightFitness/Controller/DashboardViewController.swift @@ -8,7 +8,7 @@ class DashboardViewController: UIViewController, UITableViewDelegate, UITableVie var currentIndexPath: NSIndexPath? var currentExercise: Exercise? - var timerController: TimerController? + var rootViewController: RootViewController? init() { super.init(nibName: "DashboardView", bundle: nil) @@ -20,20 +20,20 @@ class DashboardViewController: UIViewController, UITableViewDelegate, UITableVie override func viewDidLoad() { self.tableView.registerNib( - UINib(nibName: "DashboardCategoryViewCell", bundle: nil), - forCellReuseIdentifier: "DashboardCategoryViewCell") + UINib(nibName: "DashboardCategoryCell", bundle: nil), + forCellReuseIdentifier: "DashboardCategoryCell") self.tableView.registerNib( - UINib(nibName: "DashboardSectionViewCell", bundle: nil), - forCellReuseIdentifier: "DashboardSectionViewCell") + UINib(nibName: "DashboardSectionCell", bundle: nil), + forCellReuseIdentifier: "DashboardSectionCell") self.tableView.registerNib( - UINib(nibName: "DashboardSingleItemViewCell", bundle: nil), - forCellReuseIdentifier: "DashboardSingleItemViewCell") + UINib(nibName: "DashboardSingleItemCell", bundle: nil), + forCellReuseIdentifier: "DashboardSingleItemCell") self.tableView.registerNib( - UINib(nibName: "DashboardDoubleItemViewCell", bundle: nil), - forCellReuseIdentifier: "DashboardDoubleItemViewCell") + UINib(nibName: "DashboardDoubleItemCell", bundle: nil), + forCellReuseIdentifier: "DashboardDoubleItemCell") self.tableView.delegate = self self.tableView.dataSource = self @@ -83,7 +83,7 @@ class DashboardViewController: UIViewController, UITableViewDelegate, UITableVie let categoryOrSection = routine.categoriesAndSections[section] if let category = categoryOrSection as? Category { - let cell = tableView.dequeueReusableCellWithIdentifier("DashboardCategoryViewCell") as! DashboardCategoryViewCell + let cell = tableView.dequeueReusableCellWithIdentifier("DashboardCategoryCell") as! DashboardCategoryCell cell.title?.text = category.title @@ -96,7 +96,7 @@ class DashboardViewController: UIViewController, UITableViewDelegate, UITableVie } if let section = categoryOrSection as? Section { - let cell = tableView.dequeueReusableCellWithIdentifier("DashboardSectionViewCell") as! DashboardSectionViewCell + let cell = tableView.dequeueReusableCellWithIdentifier("DashboardSectionCell") as! DashboardSectionCell cell.title?.text = section.title cell.desc?.text = section.desc @@ -117,7 +117,7 @@ class DashboardViewController: UIViewController, UITableViewDelegate, UITableVie let rowIndex = indexPath.row if (rowIndex == 0) { - let cell = tableView.dequeueReusableCellWithIdentifier("DashboardSingleItemViewCell", forIndexPath: indexPath) as! DashboardSingleItemViewCell + let cell = tableView.dequeueReusableCellWithIdentifier("DashboardSingleItemCell", forIndexPath: indexPath) as! DashboardSingleItemCell let section = routine.categoriesAndSections[sectionIndex] as! Section @@ -147,7 +147,7 @@ class DashboardViewController: UIViewController, UITableViewDelegate, UITableVie let exercise = section.exercises[index] as! Exercise if let nextExercise = exercise.next { - let cell = tableView.dequeueReusableCellWithIdentifier("DashboardDoubleItemViewCell", forIndexPath: indexPath) as! DashboardDoubleItemViewCell + let cell = tableView.dequeueReusableCellWithIdentifier("DashboardDoubleItemCell", forIndexPath: indexPath) as! DashboardDoubleItemCell cell.dashboardViewController = self @@ -161,7 +161,7 @@ class DashboardViewController: UIViewController, UITableViewDelegate, UITableVie cell.leftTitle?.text = exercise.title cell.rightTitle?.text = nextExercise.title } else { - let cell = tableView.dequeueReusableCellWithIdentifier("DashboardSingleItemViewCell", forIndexPath: indexPath) as! DashboardSingleItemViewCell + let cell = tableView.dequeueReusableCellWithIdentifier("DashboardSingleItemCell", forIndexPath: indexPath) as! DashboardSingleItemCell setCurrentIndex(exercise, indexPath: indexPath) @@ -174,7 +174,7 @@ class DashboardViewController: UIViewController, UITableViewDelegate, UITableVie return cell } else { - let cell = tableView.dequeueReusableCellWithIdentifier("DashboardSingleItemViewCell", forIndexPath: indexPath) as! DashboardSingleItemViewCell + let cell = tableView.dequeueReusableCellWithIdentifier("DashboardSingleItemCell", forIndexPath: indexPath) as! DashboardSingleItemCell setCurrentIndex(exercise, indexPath: indexPath) @@ -206,7 +206,7 @@ class DashboardViewController: UIViewController, UITableViewDelegate, UITableVie } func dismissWithExercise(exercise: Exercise) { - self.timerController?.changeExercise(exercise) + self.rootViewController?.changeExercise(exercise) self.dismissViewControllerAnimated(true, completion: nil) } diff --git a/LogWorkoutController.swift b/BodyweightFitness/Controller/Modal/LogWorkoutController.swift similarity index 96% rename from LogWorkoutController.swift rename to BodyweightFitness/Controller/Modal/LogWorkoutController.swift index 5d741ab..bff1ba3 100644 --- a/LogWorkoutController.swift +++ b/BodyweightFitness/Controller/Modal/LogWorkoutController.swift @@ -107,6 +107,14 @@ class LogWorkoutController: UIViewController { decreaseWeightTimer?.invalidate() } + init() { + super.init(nibName: "LogWorkoutModalView", bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func viewDidLoad() { super.viewDidLoad() @@ -385,7 +393,15 @@ class LogWorkoutController: UIViewController { realm.add(exercise, update: true) } } - + + if let sideNavigationController = self.parentController as? SideNavigationController { + if let navigationController = sideNavigationController.rootViewController as? UINavigationController { + if let rootViewController = navigationController.viewControllers.first as? RootViewController { + rootViewController.weightedViewController.updateLabels() + } + } + } + self.parentController?.dim(.Out, alpha: 0.5, speed: 0.5) self.dismissViewControllerAnimated(true, completion: nil) @@ -550,14 +566,14 @@ class SetView: UIButton { if minutes == 0 { self.centerLabel = UILabel(frame: CGRect.init(x: 0, y: 25, width: 70, height: 20)) - self.centerLabel?.font = UIFont.boldSystemFontOfSize(14.0) + self.centerLabel?.font = UIFont.boldSystemFontOfSize(16.0) self.centerLabel?.textAlignment = NSTextAlignment.Center self.centerLabel?.text = "\(seconds)s" self.addSubview(self.centerLabel!) } else if (minutes > 0 && seconds == 0) { self.centerLabel = UILabel(frame: CGRect.init(x: 0, y: 25, width: 70, height: 20)) - self.centerLabel?.font = UIFont.boldSystemFontOfSize(14.0) + self.centerLabel?.font = UIFont.boldSystemFontOfSize(16.0) self.centerLabel?.textAlignment = NSTextAlignment.Center self.centerLabel?.text = "\(minutes)m" @@ -579,7 +595,7 @@ class SetView: UIButton { } else { if set.weight == 0 { self.centerLabel = UILabel(frame: CGRect.init(x: 0, y: 25, width: 70, height: 20)) - self.centerLabel?.font = UIFont.boldSystemFontOfSize(14.0) + self.centerLabel?.font = UIFont.boldSystemFontOfSize(16.0) self.centerLabel?.textAlignment = NSTextAlignment.Center self.centerLabel?.text = "\(set.reps)" diff --git a/BodyweightFitness/Controller/TimePickerController.swift b/BodyweightFitness/Controller/Modal/TimePickerController.swift similarity index 88% rename from BodyweightFitness/Controller/TimePickerController.swift rename to BodyweightFitness/Controller/Modal/TimePickerController.swift index 505297a..eb1f747 100644 --- a/BodyweightFitness/Controller/TimePickerController.swift +++ b/BodyweightFitness/Controller/Modal/TimePickerController.swift @@ -1,4 +1,5 @@ import UIKit +import RealmSwift class TimePickerController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate { @IBOutlet var timePickerView: UIPickerView! @@ -7,11 +8,11 @@ class TimePickerController: UIViewController, UIPickerViewDataSource, UIPickerVi var seconds: Int = 15 init() { - super.init(nibName: "TimePicker", bundle: NSBundle.mainBundle()) + super.init(nibName: "TimePickerModalView", bundle: NSBundle.mainBundle()) } required init(coder aDecoder: NSCoder) { - super.init(nibName: "TimePicker", bundle: NSBundle.mainBundle()) + super.init(nibName: "TimePickerModalView", bundle: NSBundle.mainBundle()) } override func viewDidLoad() { @@ -62,8 +63,8 @@ class TimePickerController: UIViewController, UIPickerViewDataSource, UIPickerVi var totalSeconds = (minutes * 60) + seconds - if(totalSeconds < 15) { - totalSeconds = 15 + if(totalSeconds < 5) { + totalSeconds = 5 } return totalSeconds diff --git a/BodyweightFitness/Controller/NavigationViewController.swift b/BodyweightFitness/Controller/NavigationViewController.swift new file mode 100644 index 0000000..af35041 --- /dev/null +++ b/BodyweightFitness/Controller/NavigationViewController.swift @@ -0,0 +1,15 @@ +import UIKit + +class NavigationViewController: UIViewController { + @IBOutlet var topLabel: UILabel! + @IBOutlet var bottomLeftLabel: UILabel! + @IBOutlet var bottomRightLabel: UILabel! + + init() { + super.init(nibName: "NavigationView", bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} \ No newline at end of file diff --git a/ProgressGeneralViewController.swift b/BodyweightFitness/Controller/ProgressGeneralViewController.swift similarity index 100% rename from ProgressGeneralViewController.swift rename to BodyweightFitness/Controller/ProgressGeneralViewController.swift diff --git a/ProgressPageViewController.swift b/BodyweightFitness/Controller/ProgressPageViewController.swift similarity index 76% rename from ProgressPageViewController.swift rename to BodyweightFitness/Controller/ProgressPageViewController.swift index ba9a4ef..ff472a5 100644 --- a/ProgressPageViewController.swift +++ b/BodyweightFitness/Controller/ProgressPageViewController.swift @@ -10,12 +10,12 @@ class ProgressPageViewController: UITableViewController { super.viewDidLoad() self.tableView.registerNib( - UINib(nibName: "SectionViewCell", bundle: nil), - forCellReuseIdentifier: "SectionViewCell") + UINib(nibName: "ProgressSectionCell", bundle: nil), + forCellReuseIdentifier: "ProgressSectionCell") self.tableView.registerNib( - UINib(nibName: "CardViewCell", bundle: nil), - forCellReuseIdentifier: "CardViewCell") + UINib(nibName: "ProgressCardCell", bundle: nil), + forCellReuseIdentifier: "ProgressCardCell") self.tableView.delegate = self self.tableView.dataSource = self @@ -32,7 +32,7 @@ class ProgressPageViewController: UITableViewController { override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if let category = self.category { let exercises = category.sections[section].exercises.filter { (exercise) in - exercise.visible == true + isVisible(exercise) } return exercises.count @@ -40,10 +40,6 @@ class ProgressPageViewController: UITableViewController { return 0 } - @IBAction func onClickRemove(sender: AnyObject) { - } - @IBAction func onClickExport(sender: AnyObject) { - } override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 45 @@ -54,7 +50,7 @@ class ProgressPageViewController: UITableViewController { } override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - let cell = tableView.dequeueReusableCellWithIdentifier("SectionViewCell") as! SectionViewCell + let cell = tableView.dequeueReusableCellWithIdentifier("ProgressSectionCell") as! ProgressSectionCell cell.parentController = parentController @@ -72,18 +68,18 @@ class ProgressPageViewController: UITableViewController { } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCellWithIdentifier("CardViewCell", forIndexPath: indexPath) as! CardViewCell + let cell = tableView.dequeueReusableCellWithIdentifier("ProgressCardCell", forIndexPath: indexPath) as! ProgressCardCell cell.parentController = parentController if let category = self.category { let exercises = category.sections[indexPath.section].exercises.filter { (exercise) in - exercise.visible == true + isVisible(exercise) } let exercise = exercises[indexPath.row] - cell.exercise = exercise + cell.current = exercise cell.title.text = exercise.title cell.subtitle.text = exercise.desc @@ -91,4 +87,18 @@ class ProgressPageViewController: UITableViewController { return cell } + + func isVisible(exercise: RepositoryExercise) -> Bool { + let firstSet = exercise.sets[0] + + if (exercise.sets.count > 1) { + return true + } else { + if (firstSet.seconds > 0 || firstSet.reps > 0) { + return true + } + } + + return exercise.visible + } } diff --git a/ProgressViewController.swift b/BodyweightFitness/Controller/ProgressViewController.swift similarity index 96% rename from ProgressViewController.swift rename to BodyweightFitness/Controller/ProgressViewController.swift index 73e45e0..d5c0164 100644 --- a/ProgressViewController.swift +++ b/BodyweightFitness/Controller/ProgressViewController.swift @@ -4,14 +4,14 @@ import PageMenuFramework class ProgressViewController: UIViewController { var date: NSDate? var repositoryRoutine: RepositoryRoutine? - var pageMenu : CAPSPageMenu? + var pageMenu: CAPSPageMenu? var controllerArray: [UIViewController] = [] override func viewDidLoad() { super.viewDidLoad() self.setNavigationBar() - + self.navigationItem.backBarButtonItem?.tintColor = UIColor.primaryDark() if let routine = repositoryRoutine { self.navigationItem.title = CVDate(date: routine.startTime).commonDescription } diff --git a/BodyweightFitness/Controller/RootViewController.swift b/BodyweightFitness/Controller/RootViewController.swift new file mode 100644 index 0000000..f662d32 --- /dev/null +++ b/BodyweightFitness/Controller/RootViewController.swift @@ -0,0 +1,326 @@ +import UIKit + +class RootViewController: UIViewController { + @IBOutlet var actionButton: UIButton! + @IBOutlet var topView: UIView! + @IBOutlet var middleView: UIView! + @IBOutlet var viewControl: UISegmentedControl! + @IBOutlet var mainView: UIView! + @IBOutlet var gifView: AnimatableImageView! + + @IBOutlet weak var middleViewHeightConstraint: NSLayoutConstraint! + + let navigationViewController: NavigationViewController = NavigationViewController() + let timedViewController: TimedViewController = TimedViewController() + let weightedViewController: WeightedViewController = WeightedViewController() + + var current: Exercise? + + init() { + super.init(nibName: "RootView", bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + // + // Hide switcher in iPhone 4S + // + if (UIScreen.mainScreen().bounds.size.height == 480) { + middleViewHeightConstraint.constant = 0 + middleView.hidden = true + } + + self.timedViewController.rootViewController = self + self.weightedViewController.rootViewController = self + + + + self.timedViewController.view.frame = self.topView.frame + self.timedViewController.willMoveToParentViewController(self) + + self.addChildViewController(self.timedViewController) + + self.topView.addSubview(self.timedViewController.view) + + self.timedViewController.didMoveToParentViewController(self) + + + + self.weightedViewController.view.frame = self.topView.frame + self.weightedViewController.willMoveToParentViewController(self) + + self.addChildViewController(self.weightedViewController) + + self.topView.addSubview(self.weightedViewController.view) + + self.weightedViewController.didMoveToParentViewController(self) + + + + self.setNavigationBar() + + let menuItem = UIBarButtonItem( + image: UIImage(named: "menu"), + landscapeImagePhone: nil, + style: .Plain, + target: self, + action: #selector(dismiss)) + + let dashboardItem = UIBarButtonItem( + image: UIImage(named: "dashboard"), + landscapeImagePhone: nil, + style: .Plain, + target: self, + action: #selector(dashboard)) + + self.navigationItem.leftBarButtonItem = menuItem + self.navigationItem.rightBarButtonItem = dashboardItem + self.navigationItem.titleView = navigationViewController.view + + self.timedViewController.updateLabel() + self.changeExercise(RoutineStream.sharedInstance.routine.getFirstExercise()) + + let rate = RateMyApp.sharedInstance + + rate.appID = "1018863605" + rate.trackAppUsage() + } + + override func viewDidAppear(animated: Bool) { + super.viewDidAppear(animated) + + setTitle() + } + + override func willAnimateRotationToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) { + setTitle() + } + + override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) + + setTitle() + } + + func dismiss(sender: UIBarButtonItem) { + self.sideNavigationController?.toggleLeftView() + } + + func dashboard(sender: UIBarButtonItem) { + let dashboard = DashboardViewController() + dashboard.currentExercise = current + dashboard.rootViewController = self + + let controller = UINavigationController(rootViewController: dashboard) + + self.navigationController?.presentViewController(controller, animated: true, completion: nil) + } + + @IBAction func indexChanged(sender: UISegmentedControl) { + switch sender.selectedSegmentIndex { + case 0: + self.timedViewController.stopTimer() + + self.timedViewController.view.hidden = false + self.weightedViewController.view.hidden = true + case 1: + self.timedViewController.view.hidden = true + self.weightedViewController.view.hidden = false + default: + break; + } + } + + @IBAction func onClickLogWorkoutAction(sender: AnyObject) { + self.timedViewController.stopTimer() + + let logWorkoutController = LogWorkoutController() + + logWorkoutController.parentController = self.sideNavigationController + logWorkoutController.setRepositoryRoutine(current!, repositoryRoutine: RepositoryStream.sharedInstance.getRepositoryRoutineForToday()) + + logWorkoutController.modalTransitionStyle = .CoverVertical + logWorkoutController.modalPresentationStyle = .Custom + + self.sideNavigationController?.dim(.In, alpha: 0.5, speed: 0.5) + self.sideNavigationController?.presentViewController(logWorkoutController, animated: true, completion: nil) + } + + func setTitle() { + let navigationBarSize = self.navigationController?.navigationBar.frame.size + let titleView = self.navigationItem.titleView + var titleViewFrame = titleView?.frame + titleViewFrame?.size = navigationBarSize! + self.navigationItem.titleView?.frame = titleViewFrame! + + titleView?.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleLeftMargin, UIViewAutoresizing.FlexibleRightMargin] + titleView?.autoresizesSubviews = true + } + + internal func changeExercise(currentExercise: Exercise) { + self.current = currentExercise + + self.timedViewController.changeExercise(currentExercise) + self.weightedViewController.changeExercise(currentExercise) + + self.navigationViewController.topLabel?.text = currentExercise.title + self.navigationViewController.bottomLeftLabel?.text = currentExercise.section?.title + self.navigationViewController.bottomRightLabel?.text = currentExercise.desc + + self.setGifImage(currentExercise.id) + + if (currentExercise.section?.mode == SectionMode.All) { + if let image = UIImage(named: "plus") { + actionButton.setImage(image, forState: .Normal) + } + } else { + if let image = UIImage(named: "progression") { + actionButton.setImage(image, forState: .Normal) + } + } + + if let current = self.current { + if current.isTimed() { + self.viewControl.selectedSegmentIndex = 0 + self.viewControl.setEnabled(false, forSegmentAtIndex: 1) + self.viewControl.sendActionsForControlEvents(UIControlEvents.ValueChanged) + + self.timedViewController.view.hidden = false + self.weightedViewController.view.hidden = true + } else { + self.viewControl.selectedSegmentIndex = 1 + self.viewControl.setEnabled(true, forSegmentAtIndex: 1) + self.viewControl.sendActionsForControlEvents(UIControlEvents.ValueChanged) + + self.timedViewController.view.hidden = true + self.weightedViewController.view.hidden = false + } + } + } + + func setGifImage(id: String) { + if let bundle = NSBundle.mainBundle().URLForResource(id, withExtension: "gif") { + if let imageData = NSData(contentsOfURL: bundle) { + + gifView.animateWithImageData(imageData) + } + } + } + + @IBAction func actionButtonClicked(sender: AnyObject) { + guard let button = sender as? UIView else { + return + } + + let alertController = UIAlertController( + title: nil, + message: nil, + preferredStyle: .ActionSheet) + + alertController.popoverPresentationController + alertController.modalPresentationStyle = .Popover + + if let presenter = alertController.popoverPresentationController { + presenter.sourceView = button; + presenter.sourceRect = button.bounds; + } + + // ... Cancel Action + alertController.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)) + + // ... Watch on YouTube Action + alertController.addAction( + UIAlertAction(title: "Watch on YouTube", style: .Default) { (action) in + /// ... Watch on YouTube + if let youTubeId = self.current?.youTubeId { + if let requestUrl = NSURL(string: "https://www.youtube.com/watch?v=" + youTubeId) { + UIApplication.sharedApplication().openURL(requestUrl) + } + } + } + ) + + // ... Today's Workout Action + alertController.addAction(UIAlertAction(title: "Today's Workout", style: .Default) { (action) in + let backItem = UIBarButtonItem() + backItem.title = "Back" + + self.navigationItem.backBarButtonItem = backItem + + let progressViewController = ProgressViewController() + + progressViewController.setRoutine(NSDate(), repositoryRoutine: RepositoryStream.sharedInstance.getRepositoryRoutineForToday()) + + self.showViewController(progressViewController, sender: nil) + }) + + // ... Choose Progression Action + if let currentSection = current?.section { + if (currentSection.mode == .Levels || currentSection.mode == .Pick) { + // ... Choose Progression + alertController.addAction( + UIAlertAction(title: "Choose Progression", style: .Default) { (action) in + if let exercises = self.current?.section?.exercises { + let alertController = UIAlertController( + title: "Choose Progression", + message: nil, + preferredStyle: .ActionSheet) + + alertController.modalPresentationStyle = .Popover + + if let presenter = alertController.popoverPresentationController { + presenter.sourceView = button; + presenter.sourceRect = button.bounds; + } + + alertController.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)) + + for anyExercise in exercises { + if let exercise = anyExercise as? Exercise { + var title = "" + + if(exercise.section?.mode == SectionMode.Levels) { + title = "\(exercise.level): \(exercise.title)" + } else { + title = "\(exercise.title)" + } + + alertController.addAction( + UIAlertAction(title: title, style: .Default) { (action) in + RoutineStream.sharedInstance.routine.setProgression(exercise) + + self.changeExercise(exercise) + + PersistenceManager.storeRoutine(RoutineStream.sharedInstance.routine) + } + ) + } + } + + self.presentViewController(alertController, animated: true, completion: nil) + } + } + ) + } + } + + self.presentViewController(alertController, animated: true, completion: nil) + } + + @IBAction func previousButtonClicked(sender: AnyObject) { + if let previous = self.current?.previous { + changeExercise(previous) + } + } + + @IBAction func nextButtonClicked(sender: AnyObject) { + if let next = self.current?.next { + changeExercise(next) + } + } + } \ No newline at end of file diff --git a/BodyweightFitness/Service/PersistenceManager.swift b/BodyweightFitness/Controller/Service/PersistenceManager.swift similarity index 74% rename from BodyweightFitness/Service/PersistenceManager.swift rename to BodyweightFitness/Controller/Service/PersistenceManager.swift index 81b26f3..0244ad0 100644 --- a/BodyweightFitness/Service/PersistenceManager.swift +++ b/BodyweightFitness/Controller/Service/PersistenceManager.swift @@ -28,11 +28,34 @@ class PersistenceManager { NSKeyedArchiver.archiveRootObject(weightUnit, toFile: dataFilePath) } - class func getTimer() -> Int { + class func getNumberOfReps(id: String) -> Int { let fileManager = NSFileManager.defaultManager() let directoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) let documentsDirectory = directoryPath[0] - let dataFilePath = documentsDirectory.NS.stringByAppendingPathComponent("timer.archive") + let dataFilePath = documentsDirectory.NS.stringByAppendingPathComponent("reps.\(id).archive") + + if(fileManager.fileExistsAtPath(dataFilePath)) { + if let seconds = NSKeyedUnarchiver.unarchiveObjectWithFile(dataFilePath) as? Int { + return seconds + } + } + + return 5 + } + + class func storeNumberOfReps(id: String, numberOfReps: Int) { + let directoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) + let documentsDirectory = directoryPath[0] + let dataFilePath = documentsDirectory.NS.stringByAppendingPathComponent("reps.\(id).archive") + + NSKeyedArchiver.archiveRootObject(numberOfReps, toFile: dataFilePath) + } + + class func getTimer(id: String) -> Int { + let fileManager = NSFileManager.defaultManager() + let directoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) + let documentsDirectory = directoryPath[0] + let dataFilePath = documentsDirectory.NS.stringByAppendingPathComponent("timer.\(id).archive") if(fileManager.fileExistsAtPath(dataFilePath)) { if let seconds = NSKeyedUnarchiver.unarchiveObjectWithFile(dataFilePath) as? Int { @@ -43,10 +66,10 @@ class PersistenceManager { return 60 } - class func storeTimer(seconds: Int) { + class func storeTimer(id: String, seconds: Int) { let directoryPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) let documentsDirectory = directoryPath[0] - let dataFilePath = documentsDirectory.NS.stringByAppendingPathComponent("timer.archive") + let dataFilePath = documentsDirectory.NS.stringByAppendingPathComponent("timer.\(id).archive") NSKeyedArchiver.archiveRootObject(seconds, toFile: dataFilePath) } diff --git a/RepositoryStream.swift b/BodyweightFitness/Controller/Service/RepositoryStream.swift similarity index 90% rename from RepositoryStream.swift rename to BodyweightFitness/Controller/Service/RepositoryStream.swift index 199773f..d128e43 100644 --- a/RepositoryStream.swift +++ b/BodyweightFitness/Controller/Service/RepositoryStream.swift @@ -25,6 +25,24 @@ class RepositoryStream { return realm } + func repositoryRoutineForTodayExists() -> Bool { + let startOfDay = NSCalendar.currentCalendar().startOfDayForDate(NSDate()) + + let components = NSDateComponents() + components.hour = 23 + components.minute = 59 + components.second = 59 + + let endOfDay = NSCalendar.currentCalendar().dateByAddingComponents(components, toDate: startOfDay, options: NSCalendarOptions(rawValue: 0)) + let predicate = NSPredicate(format: "startTime > %@ AND startTime < %@", startOfDay, endOfDay!) + + if let _ = getRealm().objects(RepositoryRoutine).filter(predicate).first { + return true + } else { + return false + } + } + func getRepositoryRoutineForToday() -> RepositoryRoutine { // If you want to get objects after a date, use greater-than (>), for dates before, use less-than (<). let startOfDay = NSCalendar.currentCalendar().startOfDayForDate(NSDate()) diff --git a/RoutineStream.swift b/BodyweightFitness/Controller/Service/RoutineStream.swift similarity index 100% rename from RoutineStream.swift rename to BodyweightFitness/Controller/Service/RoutineStream.swift diff --git a/BodyweightFitness/Controller/SettingsController.swift b/BodyweightFitness/Controller/SettingsController.swift deleted file mode 100755 index e8c1d12..0000000 --- a/BodyweightFitness/Controller/SettingsController.swift +++ /dev/null @@ -1,29 +0,0 @@ -import UIKit - -class SettingsController: UITableViewController { - @IBOutlet var playAudioWhenTimerStops: UISwitch! - - override func viewDidLoad() { - super.viewDidLoad() - - self.setNavigationBar() - - let defaults = NSUserDefaults.standardUserDefaults() - if(defaults.objectForKey("playAudioWhenTimerStops") != nil) { - self.playAudioWhenTimerStops.on = defaults.boolForKey("playAudioWhenTimerStops") - } - } - - @IBAction func onClickNavigationItem(sender: AnyObject) { - self.sideNavigationController?.toggleLeftView() - } - - @IBAction func playAudioWhenTimerStopsChanged(sender: AnyObject) { - let defaults = NSUserDefaults.standardUserDefaults() - if self.playAudioWhenTimerStops.on { - defaults.setBool(true, forKey: "playAudioWhenTimerStops") - } else { - defaults.setBool(false, forKey: "playAudioWhenTimerStops") - } - } -} \ No newline at end of file diff --git a/BodyweightFitness/Controller/SettingsViewController.swift b/BodyweightFitness/Controller/SettingsViewController.swift new file mode 100755 index 0000000..40f1207 --- /dev/null +++ b/BodyweightFitness/Controller/SettingsViewController.swift @@ -0,0 +1,306 @@ +import UIKit +import StoreKit + +class SettingsToggleCell: UITableViewCell { + @IBOutlet var label: UILabel! + @IBOutlet var toggle: UISwitch! + + override func awakeFromNib() { + super.awakeFromNib() + } +} + +class SettingsActionCell: UITableViewCell { + override func awakeFromNib() { + super.awakeFromNib() + } +} + +class SettingsActionSubtitleCell: UITableViewCell { + override func awakeFromNib() { + super.awakeFromNib() + } +} + +class SettingsTextCell: UITableViewCell { + override func awakeFromNib() { + super.awakeFromNib() + } +} + +extension UIViewController { + func registerNib(tableView: UITableView, nibName: String) { + tableView.registerNib(UINib(nibName: nibName, bundle: nil), forCellReuseIdentifier: nibName) + } +} + +class SettingsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, SKStoreProductViewControllerDelegate { + @IBOutlet var tableView: UITableView! + + init() { + super.init(nibName: "SettingsView", bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + self.setNavigationBar() + + self.registerNib(self.tableView, nibName: "SettingsSectionCell") + self.registerNib(self.tableView, nibName: "SettingsToggleCell") + self.registerNib(self.tableView, nibName: "SettingsActionCell") + self.registerNib(self.tableView, nibName: "SettingsActionSubtitleCell") + self.registerNib(self.tableView, nibName: "SettingsTextCell") + + self.tableView.delegate = self + self.tableView.dataSource = self + + let menuItem = UIBarButtonItem( + image: UIImage(named: "menu"), + landscapeImagePhone: nil, + style: .Plain, + target: self, + action: #selector(dismiss)) + + menuItem.tintColor = UIColor.primaryDark() + + self.navigationItem.leftBarButtonItem = menuItem + self.navigationItem.title = "Settings" + } + + func dismiss(sender: UIBarButtonItem) { + self.sideNavigationController?.toggleLeftView() + } + + func playAudioWhenTimerStops(sender: UISwitch) { + if sender.on { + let defaults = NSUserDefaults.standardUserDefaults() + defaults.setBool(true, forKey: "playAudioWhenTimerStops") + } else { + let defaults = NSUserDefaults.standardUserDefaults() + defaults.setBool(false, forKey: "playAudioWhenTimerStops") + } + } + + func openStoreProductWithiTunesItemIdentifier(identifier: String) { + let storeViewController = SKStoreProductViewController() + storeViewController.delegate = self + + let parameters = [ SKStoreProductParameterITunesItemIdentifier : identifier] + storeViewController.loadProductWithParameters(parameters) { [weak self] (loaded, error) -> Void in + if loaded { + // Parent class of self is UIViewContorller + self?.presentViewController(storeViewController, animated: true, completion: nil) + } + } + } + + func numberOfSectionsInTableView(tableView: UITableView) -> Int { + return 6 + } + + func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if (section == 4) { + return 2 + } + + return 1 + } + + func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + switch section { + case 0: + return "General" + case 1: + return "Weight Measurement" + case 2: + return "Developed by" + case 3: + return "Credits" + case 4: + return "About" + case 5: + return "Version" + default: + return nil + } + } + + func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String? { + if section == 0 { + return "Any music playing in the background will automatically resume." + } + + return nil + } + + func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + if indexPath.section == 0 { + let cell = tableView.dequeueReusableCellWithIdentifier("SettingsToggleCell", forIndexPath: indexPath) as! SettingsToggleCell + let toggle = UISwitch() + + if indexPath.row == 0 { + cell.textLabel?.text = "Play Audio" + cell.detailTextLabel?.text = "Play audio when timer stops" + + let defaults = NSUserDefaults.standardUserDefaults() + if (defaults.objectForKey("playAudioWhenTimerStops") != nil) { + toggle.on = defaults.boolForKey("playAudioWhenTimerStops") + } + + toggle.addTarget(self, action: #selector(playAudioWhenTimerStops), forControlEvents: UIControlEvents.ValueChanged) + } + + cell.accessoryView = toggle + + return cell + } + + if indexPath.section == 1 { + let cell = tableView.dequeueReusableCellWithIdentifier("SettingsActionCell", forIndexPath: indexPath) as UITableViewCell! + + if PersistenceManager.getWeightUnit() == "lbs" { + cell.textLabel?.text = "Pounds (lbs)" + } else { + cell.textLabel?.text = "Kilograms (kg)" + } + + return cell + } + + if indexPath.section == 2 { + let cell = tableView.dequeueReusableCellWithIdentifier("SettingsActionSubtitleCell", forIndexPath: indexPath) as UITableViewCell! + + cell.textLabel?.text = "Damian Mazurkiewicz" + cell.detailTextLabel?.text = "github.com/mazurio" + + return cell + } + + if indexPath.section == 3 { + if indexPath.row == 0 { + let cell = tableView.dequeueReusableCellWithIdentifier("SettingsActionSubtitleCell", forIndexPath: indexPath) as UITableViewCell! + + cell.textLabel?.text = "Ruben Dantuma" + cell.detailTextLabel?.text = "Logo Design" + + return cell + } + } + + if indexPath.section == 4 { + if indexPath.row == 0 { + let cell = tableView.dequeueReusableCellWithIdentifier("SettingsActionCell", forIndexPath: indexPath) as UITableViewCell! + + cell.textLabel?.text = "Rate the app in iTunes Store" + + return cell + } + + if indexPath.row == 1 { + let cell = tableView.dequeueReusableCellWithIdentifier("SettingsActionCell", forIndexPath: indexPath) as UITableViewCell! + + cell.textLabel?.text = "Frequently Asked Questions" + + return cell + } + } + + let cell = tableView.dequeueReusableCellWithIdentifier("SettingsTextCell", forIndexPath: indexPath) as UITableViewCell! + + if let anyObject = NSBundle.mainBundle().infoDictionary?["CFBundleShortVersionString"] { + if let version: String = anyObject as? String { + cell.textLabel?.text = "Bodyweight Fitness" + cell.detailTextLabel?.text = version + } + } else { + cell.textLabel?.text = "Bodyweight Fitness" + } + + return cell + } + + func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { + if indexPath.section == 1 && indexPath.row == 0 { + let cell = tableView.dequeueReusableCellWithIdentifier("SettingsActionCell", forIndexPath: indexPath) as UITableViewCell! + + if PersistenceManager.getWeightUnit() == "lbs" { + cell.textLabel?.text = "Pounds (lbs)" + } else { + cell.textLabel?.text = "Kilograms (kg)" + } + + let alertController = UIAlertController( + title: nil, + message: nil, + preferredStyle: .ActionSheet) + + alertController.modalPresentationStyle = .Popover + + if let presenter = alertController.popoverPresentationController { + presenter.sourceView = cell; + presenter.sourceRect = cell.bounds; + } + + alertController.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)) + alertController.addAction(UIAlertAction(title: "Kilograms (kg)", style: .Default) { (action) in + PersistenceManager.setWeightUnit("kg") + + self.tableView.deselectRowAtIndexPath(indexPath, animated: true) + self.tableView.reloadData() + }) + alertController.addAction(UIAlertAction(title: "Pounds (lbs)", style: .Default) { (action) in + PersistenceManager.setWeightUnit("lbs") + + self.tableView.deselectRowAtIndexPath(indexPath, animated: true) + self.tableView.reloadData() + }) + + self.presentViewController(alertController, animated: true, completion: nil) + } + + if indexPath.section == 2 { + if indexPath.row == 0 { + if let requestUrl = NSURL(string: "https://www.github.com/mazurio") { + UIApplication.sharedApplication().openURL(requestUrl) + } + + self.tableView.deselectRowAtIndexPath(indexPath, animated: true) + } + } + + if indexPath.section == 3 { + if indexPath.row == 0 { + if let requestUrl = NSURL(string: "http://dantuma.co.za") { + UIApplication.sharedApplication().openURL(requestUrl) + } + + self.tableView.deselectRowAtIndexPath(indexPath, animated: true) + } + } + + if indexPath.section == 4 { + if indexPath.row == 0 { + self.openStoreProductWithiTunesItemIdentifier("1018863605") + + self.tableView.deselectRowAtIndexPath(indexPath, animated: true) + } + + if indexPath.row == 1 { + if let requestUrl = NSURL(string: "http://www.reddit.com/r/bodyweightfitness/wiki/faq") { + UIApplication.sharedApplication().openURL(requestUrl) + } + + self.tableView.deselectRowAtIndexPath(indexPath, animated: true) + } + } + + self.tableView.deselectRowAtIndexPath(indexPath, animated: true) + } + + func productViewControllerDidFinish(viewController: SKStoreProductViewController) { + viewController.dismissViewControllerAnimated(true, completion: nil) + } +} \ No newline at end of file diff --git a/SideViewController.swift b/BodyweightFitness/Controller/SideViewController.swift similarity index 78% rename from SideViewController.swift rename to BodyweightFitness/Controller/SideViewController.swift index b5a022d..6ac2a17 100644 --- a/SideViewController.swift +++ b/BodyweightFitness/Controller/SideViewController.swift @@ -1,39 +1,33 @@ import UIKit -class HeaderCell: UITableViewCell { - @IBOutlet weak var arrowButton: UIButton! - - override func awakeFromNib() { - super.awakeFromNib() - } -} - class SideViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UIGestureRecognizerDelegate { @IBOutlet var tableView: UITableView! var appDelegate: AppDelegate? - var headerCell: UITableViewCell? + init() { + super.init(nibName: "SideView", bundle: nil) + } - let menuCellIdentifier = "MenuCell" - let headerCellIdentifier = "HeaderCell" + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } override func viewDidLoad() { super.viewDidLoad() - appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate + self.appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate - tableView.delegate = self - tableView.dataSource = self - } - - func timerController() -> TimerController? { - if let timerController = - (sideNavigationController?.rootViewController as? UINavigationController)?.viewControllers[0] as? TimerController { - return timerController - } else { - return nil - } + self.tableView.registerNib( + UINib(nibName: "SideViewHeaderCell", bundle: nil), + forCellReuseIdentifier: "SideViewHeaderCell") + + self.tableView.registerNib( + UINib(nibName: "SideViewMenuCell", bundle: nil), + forCellReuseIdentifier: "SideViewMenuCell") + + self.tableView.delegate = self + self.tableView.dataSource = self } func numberOfSectionsInTableView(tableView: UITableView) -> Int { @@ -49,7 +43,7 @@ class SideViewController: UIViewController, UITableViewDataSource, UITableViewDe } func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - let cell = tableView.dequeueReusableCellWithIdentifier(headerCellIdentifier) as UITableViewCell! + let cell = tableView.dequeueReusableCellWithIdentifier("SideViewHeaderCell") as UITableViewCell! cell.backgroundColor = UIColor(red:0, green:0.59, blue:0.53, alpha:1) cell.contentView.backgroundColor = UIColor(red:0, green:0.59, blue:0.53, alpha:1) @@ -62,7 +56,7 @@ class SideViewController: UIViewController, UITableViewDataSource, UITableViewDe } func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCellWithIdentifier(menuCellIdentifier, forIndexPath: indexPath) as UITableViewCell! + let cell = tableView.dequeueReusableCellWithIdentifier("SideViewMenuCell", forIndexPath: indexPath) as UITableViewCell! switch(indexPath.row) { case 0: @@ -95,12 +89,12 @@ class SideViewController: UIViewController, UITableViewDataSource, UITableViewDe case 0: // Home - if(sideNavigationController?.rootViewController == (appDelegate?.mainViewController)!) { + if(sideNavigationController?.rootViewController == (appDelegate?.rootViewController)!) { break; } sideNavigationController?.transitionFromRootViewController( - (appDelegate?.mainViewController)!, + (appDelegate?.rootViewController)!, duration: 0, options: UIViewAnimationOptions.CurveEaseIn, animations: nil, @@ -111,12 +105,12 @@ class SideViewController: UIViewController, UITableViewDataSource, UITableViewDe case 1: // Workout Log - if(sideNavigationController?.rootViewController == (appDelegate?.calendarViewController)!) { + if(sideNavigationController?.rootViewController == (appDelegate?.workoutLogViewController)!) { break; } sideNavigationController?.transitionFromRootViewController( - (appDelegate?.calendarViewController)!, + (appDelegate?.workoutLogViewController)!, duration: 0, options: UIViewAnimationOptions.CurveEaseIn, animations: nil, diff --git a/SupportDeveloperViewController.swift b/BodyweightFitness/Controller/SupportDeveloperViewController.swift similarity index 82% rename from SupportDeveloperViewController.swift rename to BodyweightFitness/Controller/SupportDeveloperViewController.swift index e3c91bc..f748074 100644 --- a/SupportDeveloperViewController.swift +++ b/BodyweightFitness/Controller/SupportDeveloperViewController.swift @@ -1,5 +1,6 @@ import UIKit import StoreKit +import Crashlytics extension SKProduct { func localizedPrice() -> String { @@ -10,6 +11,15 @@ extension SKProduct { return formatter.stringFromNumber(self.price)! } + + func currency() -> String { + let formatter = NSNumberFormatter() + + formatter.numberStyle = .CurrencyStyle + formatter.locale = self.priceLocale + + return formatter.internationalCurrencySymbol + } } class SupportDeveloperViewController: UIViewController, SKPaymentTransactionObserver, SKProductsRequestDelegate { @@ -87,7 +97,22 @@ class SupportDeveloperViewController: UIViewController, SKPaymentTransactionObse func paymentQueue(queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) { for transaction in transactions { switch transaction.transactionState { - case .Purchased, .Restored: + case .Purchased: + self.purchased() + + if let product = product { + Answers.logPurchaseWithPrice( + product.price, + currency: product.currency(), + success: true, + itemName: "Bodyweight Fitness Gold", + itemType: "IAP", + itemId: "bodyweight.fitness.gold", + customAttributes: nil) + } + + SKPaymentQueue.defaultQueue().finishTransaction(transaction) + case .Restored: self.purchased() SKPaymentQueue.defaultQueue().finishTransaction(transaction) diff --git a/BodyweightFitness/Controller/TimedViewController.swift b/BodyweightFitness/Controller/TimedViewController.swift new file mode 100644 index 0000000..1dc47ef --- /dev/null +++ b/BodyweightFitness/Controller/TimedViewController.swift @@ -0,0 +1,270 @@ +import UIKit +import AVFoundation + +class TimedViewController: UIViewController, AVAudioPlayerDelegate { + @IBOutlet var timerMinutesButton: UIButton! + @IBOutlet var timerSecondsButton: UIButton! + + @IBOutlet var timerPlayButton: UIButton! + + @IBOutlet var previousButton: UIButton! + @IBOutlet var nextButton: UIButton! + + var rootViewController: RootViewController? = nil + var current: Exercise? = nil + + var audioPlayer: AVAudioPlayer? + var timePickerController: TimePickerController? + var timer = NSTimer() + var isPlaying = false + + var seconds = 60 + var defaultSeconds = 60 + var loggedSeconds = 0 + + init() { + super.init(nibName: "TimedView", bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + } + + func changeExercise(currentExercise: Exercise) { + self.current = currentExercise + + let savedSeconds = PersistenceManager.getTimer(currentExercise.id) + + self.loggedSeconds = 0 + self.defaultSeconds = savedSeconds + + self.restartTimer(savedSeconds) + + if let _ = self.current?.previous { + self.previousButton.hidden = false + } else { + self.previousButton.hidden = true + } + + if let _ = self.current?.next { + self.nextButton.hidden = false + } else { + self.nextButton.hidden = true + } + } + + func updateLabel() { + let (_, m, s) = secondsToHoursMinutesSeconds(seconds) + + timerMinutesButton.setTitle(printTimerValue(m), forState: UIControlState.Normal) + timerSecondsButton.setTitle(printTimerValue(s), forState: UIControlState.Normal) + } + + func printTimerValue(value: Int) -> String { + if(value > 9) { + return String(value) + } else { + return "0" + String(value) + } + } + + func secondsToHoursMinutesSeconds (seconds : Int) -> (Int, Int, Int) { + return (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60) + } + + func stopTimer() { + isPlaying = false + + timerPlayButton.setImage( + UIImage(named: "play") as UIImage?, + forState: UIControlState.Normal) + + timer.invalidate() + + self.logSeconds() + } + + func startTimer() { + isPlaying = true + + timerPlayButton.setImage( + UIImage(named: "pause") as UIImage?, + forState: UIControlState.Normal) + + timer = NSTimer.scheduledTimerWithTimeInterval( + 1, + target: self, + selector: #selector(updateTimer), + userInfo: nil, + repeats: true + ) + } + + func restartTimer(seconds: Int) { + stopTimer() + + self.seconds = seconds + self.logSeconds() + + updateLabel() + } + + func updateTimer() { + seconds -= 1 + loggedSeconds += 1 + + if(seconds <= 0) { + restartTimer(defaultSeconds) + + let defaults = NSUserDefaults.standardUserDefaults() + if(defaults.objectForKey("playAudioWhenTimerStops") != nil) { + let playAudioWhenTimerStops = defaults.boolForKey("playAudioWhenTimerStops") + if(playAudioWhenTimerStops) { + audioPlayerStart() + } + } else { + audioPlayerStart() + } + } + + updateLabel() + } + func setTimeAction() { + if let seconds = self.timePickerController?.getTotalSeconds() { + self.defaultSeconds = seconds + self.restartTimer(seconds) + + if let current = self.current { + PersistenceManager.storeTimer(current.id, seconds: self.defaultSeconds) + } + } + } + + func logSeconds() { + if let current = self.rootViewController?.current { + if (loggedSeconds > 1 && current.isTimed()) { + let realm = RepositoryStream.sharedInstance.getRealm() + let repositoryRoutine = RepositoryStream.sharedInstance.getRepositoryRoutineForToday() + + if let repositoryExercise = repositoryRoutine.exercises.filter({ + $0.exerciseId == current.exerciseId + }).first { + let sets = repositoryExercise.sets + + try! realm.write { + if (sets.count == 1 && sets[0].seconds == 0) { + sets[0].seconds = loggedSeconds + + showNotification(loggedSeconds) + } else if (sets.count >= 1 && sets.count < 9) { + let repositorySet = RepositorySet() + + repositorySet.exercise = repositoryExercise + repositorySet.isTimed = true + repositorySet.seconds = loggedSeconds + + sets.append(repositorySet) + + repositoryRoutine.lastUpdatedTime = NSDate() + + showNotification(loggedSeconds) + } + + realm.add(repositoryRoutine, update: true) + } + } + } + + } + + loggedSeconds = 0 + } + + func audioPlayerStart() { + let alertSound = NSURL(fileURLWithPath: NSBundle + .mainBundle() + .pathForResource("finished", ofType: "mp3")!) + + do { + try AVAudioSession.sharedInstance().setActive(true) + + audioPlayer = try AVAudioPlayer(contentsOfURL: alertSound, fileTypeHint: nil) + audioPlayer?.delegate = self + audioPlayer?.prepareToPlay() + audioPlayer?.play() + } catch { + print("AVAudioSession errors.") + } + } + + func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) { + do { + try AVAudioSession.sharedInstance().setActive(false, withOptions: + AVAudioSessionSetActiveOptions.NotifyOthersOnDeactivation) + } catch { + print("AVAudioSession errors.") + } + } + + func showNotification(seconds: Int) { + let notification = CWStatusBarNotification() + + notification.notificationLabelFont = UIFont.boldSystemFontOfSize(17) + notification.notificationLabelBackgroundColor = UIColor.primary() + notification.notificationLabelTextColor = UIColor.primaryDark() + + notification.notificationStyle = .NavigationBarNotification + notification.notificationAnimationInStyle = .Top + notification.notificationAnimationOutStyle = .Top + + notification.displayNotificationWithMessage("Logged \(seconds) seconds", forDuration: 2.0) + } + + @IBAction func increaseButton(sender: AnyObject) { + seconds += 5 + updateLabel() + } + + @IBAction func playButton(sender: AnyObject) { + if(isPlaying) { + stopTimer() + } else { + startTimer() + } + } + + @IBAction func restartButton(sender: AnyObject) { + restartTimer(defaultSeconds) + } + + @IBAction func timerButton(sender: AnyObject) { + stopTimer() + + timePickerController = TimePickerController() + timePickerController?.setDefaultTimer(self.seconds) + + let alertController = UIAlertController(title: "", message: "", preferredStyle: UIAlertControllerStyle.Alert) + + let setTimeAlertAction = UIAlertAction( + title: "Set Timer", + style: UIAlertActionStyle.Default) { action -> Void in self.setTimeAction() } + + alertController.setValue(timePickerController, forKey: "contentViewController"); + alertController.addAction(setTimeAlertAction) + + self.parentViewController?.presentViewController(alertController, animated: true, completion: nil) + } + + + @IBAction func previousButtonClicked(sender: AnyObject) { + self.rootViewController?.previousButtonClicked(sender) + } + + @IBAction func nextButtonClicked(sender: AnyObject) { + self.rootViewController?.nextButtonClicked(sender) + } +} \ No newline at end of file diff --git a/BodyweightFitness/Controller/TimerController.swift b/BodyweightFitness/Controller/TimerController.swift deleted file mode 100755 index d063559..0000000 --- a/BodyweightFitness/Controller/TimerController.swift +++ /dev/null @@ -1,482 +0,0 @@ -import UIKit -import AVFoundation -import SwiftCharts - -class TimerController: UIViewController, AVAudioPlayerDelegate { - @IBOutlet var exerciseTitle: UILabel! - @IBOutlet var sectionTitle: UILabel! - @IBOutlet var exerciseDescription: UILabel! - - @IBOutlet var menuButton: UIBarButtonItem! - @IBOutlet var dashboardButton: UIBarButtonItem! - - @IBOutlet var actionButton: UIButton! - @IBOutlet var timerMinutesButton: UIButton! - @IBOutlet var timerButton: UIButton! - @IBOutlet var mainView: UIView! - @IBOutlet var gifView: AnimatableImageView! - @IBOutlet var previousButton: UIButton! - @IBOutlet var nextButton: UIButton! - @IBOutlet var playButton: UIButton! - - var timePickerController: TimePickerController? - var timer = NSTimer() - var isPlaying = false - var seconds = PersistenceManager.getTimer() - var defaultSeconds = PersistenceManager.getTimer() - var loggedSeconds = 0 - - var current: Exercise? - - var audioPlayer: AVAudioPlayer? - - @IBAction func onClickMenuAction(sender: AnyObject) { - self.sideNavigationController?.toggleLeftView() - } - - @IBAction func onClickDashboardAction(sender: AnyObject) { - let dashboard = DashboardViewController() - dashboard.currentExercise = current - dashboard.timerController = self - - let controller = UINavigationController(rootViewController: dashboard) - - self.navigationController?.presentViewController(controller, animated: true, completion: nil) - } - - @IBAction func onClickLogWorkoutAction(sender: AnyObject) { - self.stopTimer() - - let logWorkoutController = self.storyboard!.instantiateViewControllerWithIdentifier("LogWorkoutController") as! LogWorkoutController - - logWorkoutController.parentController = self.navigationController - logWorkoutController.setRepositoryRoutine(current!, repositoryRoutine: RepositoryStream.sharedInstance.getRepositoryRoutineForToday()) - - self.navigationController?.modalTransitionStyle = UIModalTransitionStyle.CoverVertical - self.navigationController?.modalPresentationStyle = .CurrentContext - self.navigationController?.dim(.In, alpha: 0.5, speed: 0.5) - self.navigationController?.presentViewController(logWorkoutController, animated: true, completion: nil) - } - - override func viewDidLoad() { - super.viewDidLoad() - - self.setNavigationBar() - - mainView.backgroundColor = UIColor(red:0, green:0.59, blue:0.53, alpha:1) - - setNavigationBar() - updateLabel() - changeExercise(RoutineStream.sharedInstance.routine.getFirstExercise()) - } - - override func viewDidAppear(animated: Bool) { - super.viewDidAppear(animated) - - setTitle() - } - - override func willAnimateRotationToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) { - setTitle() - } - - override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { - super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) - - setTitle() - } - - func showNotification(seconds: Int) { - let notification = CWStatusBarNotification() - notification.notificationLabelFont = UIFont.systemFontOfSize(17) - notification.notificationLabelBackgroundColor = UIColor.primary() - notification.notificationLabelTextColor = UIColor.primaryDark() - - notification.notificationStyle = .NavigationBarNotification - notification.notificationAnimationInStyle = .Top - notification.notificationAnimationOutStyle = .Top - - notification.displayNotificationWithMessage("Logged \(seconds) seconds", forDuration: 2.0) - } - - func setTitle() { - let navigationBarSize = self.navigationController?.navigationBar.frame.size - let titleView = self.navigationItem.titleView - var titleViewFrame = titleView?.frame - titleViewFrame?.size = navigationBarSize! - self.navigationItem.titleView?.frame = titleViewFrame! - - titleView?.autoresizingMask = [UIViewAutoresizing.FlexibleWidth, UIViewAutoresizing.FlexibleLeftMargin, UIViewAutoresizing.FlexibleRightMargin] - titleView?.autoresizesSubviews = true - } - - internal func changeExercise(currentExercise: Exercise) { - self.loggedSeconds = 0 - - self.current = currentExercise - - self.exerciseTitle.text = currentExercise.title - self.exerciseDescription.text = currentExercise.desc - self.sectionTitle.text = currentExercise.section?.title - - restartTimer(defaultSeconds) - setGifImage(currentExercise.id) - - if (currentExercise.section?.mode == SectionMode.All) { - if let image = UIImage(named: "plus") { - actionButton.setImage(image, forState: .Normal) - } - } else { - if let image = UIImage(named: "progression") { - actionButton.setImage(image, forState: .Normal) - } - } - - if let _ = self.current?.previous { - previousButton.hidden = false - } else { - previousButton.hidden = true - } - - if let _ = self.current?.next { - nextButton.hidden = false - } else { - nextButton.hidden = true - } - } - - func setGifImage(id: String) { - let imageData = NSData(contentsOfURL: NSBundle - .mainBundle() - .URLForResource(id, withExtension: "gif")!) - - gifView.animateWithImageData(imageData!) - } - - @IBAction func actionButtonClicked(sender: AnyObject) { - guard let button = sender as? UIView else { - return - } - - let alertController = UIAlertController( - title: nil, - message: nil, - preferredStyle: .ActionSheet) - - alertController.popoverPresentationController - alertController.modalPresentationStyle = .Popover - - if let presenter = alertController.popoverPresentationController { - presenter.sourceView = button; - presenter.sourceRect = button.bounds; - } - - // ... Cancel Action - alertController.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)) - - // ... Watch on YouTube Action - alertController.addAction( - UIAlertAction(title: "Watch on YouTube", style: .Default) { (action) in - /// ... Watch on YouTube - if let youTubeId = self.current?.youTubeId { - if let requestUrl = NSURL(string: "https://www.youtube.com/watch?v=" + youTubeId) { - UIApplication.sharedApplication().openURL(requestUrl) - } - } - } - ) - - // ... Today's Workout Action - alertController.addAction(UIAlertAction(title: "Today's Workout", style: .Default) { (action) in - let backItem = UIBarButtonItem() - backItem.title = "Back" - - self.navigationItem.backBarButtonItem = backItem - - let progressViewController = self.storyboard!.instantiateViewControllerWithIdentifier("ProgressViewController") as! ProgressViewController - - progressViewController.setRoutine(NSDate(), repositoryRoutine: RepositoryStream.sharedInstance.getRepositoryRoutineForToday()) - - self.showViewController(progressViewController, sender: nil) - } - ) - - // ... Choose Progression Action - if let currentSection = current?.section { - if (currentSection.mode == .Levels || currentSection.mode == .Pick) { - // ... Choose Progression - alertController.addAction( - UIAlertAction(title: "Choose Progression", style: .Default) { (action) in - if let exercises = self.current?.section?.exercises { - let alertController = UIAlertController( - title: "Choose Progression", - message: nil, - preferredStyle: .ActionSheet) - - alertController.modalPresentationStyle = .Popover - - if let presenter = alertController.popoverPresentationController { - presenter.sourceView = button; - presenter.sourceRect = button.bounds; - } - - alertController.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)) - - for anyExercise in exercises { - if let exercise = anyExercise as? Exercise { - var title = "" - - if(exercise.section?.mode == SectionMode.Levels) { - title = "\(exercise.level): \(exercise.title)" - } else { - title = "\(exercise.title)" - } - - alertController.addAction( - UIAlertAction(title: title, style: .Default) { (action) in - RoutineStream.sharedInstance.routine.setProgression(exercise) - - self.changeExercise(exercise) - - PersistenceManager.storeRoutine(RoutineStream.sharedInstance.routine) - } - ) - } - } - - self.presentViewController(alertController, animated: true, completion: nil) - } - } - ) - } - } - - self.presentViewController(alertController, animated: true, completion: nil) - } - - /// - /// Previous exercise button. - /// - @IBAction func previousButtonClicked(sender: AnyObject) { - if let previous = self.current?.previous { - changeExercise(previous) - } - } - - /// - /// Next exercise button. - /// - @IBAction func nextButtonClicked(sender: AnyObject) { - if let next = self.current?.next { - changeExercise(next) - } - } - - /// - /// Callback from alert action that time has been set. - /// - func setTimeAction() { - if let seconds = self.timePickerController?.getTotalSeconds() { - self.defaultSeconds = seconds - self.restartTimer(seconds) - - PersistenceManager.storeTimer(self.defaultSeconds) - } - } - - /// - /// Timer button that opens popup picker. - /// - @IBAction func timerButton(sender: AnyObject) { - stopTimer() - - timePickerController = TimePickerController() - timePickerController?.setDefaultTimer(self.seconds) - - let alertController = UIAlertController(title: "", message: "", preferredStyle: UIAlertControllerStyle.Alert) - - let setTimeAlertAction = UIAlertAction( - title: "Set Timer", - style: UIAlertActionStyle.Default) { action -> Void in self.setTimeAction() } - - alertController.setValue(timePickerController, forKey: "contentViewController"); - alertController.addAction(setTimeAlertAction) - - self.parentViewController?.presentViewController(alertController, animated: true, completion: nil) - } - - @IBAction func increaseButton(sender: AnyObject) { - seconds += 5 - updateLabel() - } - - @IBAction func playButton(sender: AnyObject) { - if(isPlaying) { - stopTimer() - } else { - startTimer() - } - } - - @IBAction func restartButton(sender: AnyObject) { - restartTimer(defaultSeconds) - } - - func stopTimer() { - isPlaying = false - - playButton.setImage( - UIImage(named: "play") as UIImage?, - forState: UIControlState.Normal) - - timer.invalidate() - - self.logSeconds() - } - - func startTimer() { - isPlaying = true - - playButton.setImage( - UIImage(named: "pause") as UIImage?, - forState: UIControlState.Normal) - - timer = NSTimer.scheduledTimerWithTimeInterval( - 1, - target: self, - selector: #selector(TimerController.updateTimer), - userInfo: nil, - repeats: true - ) - } - - func restartTimer(seconds: Int) { - stopTimer() - - self.seconds = seconds - self.logSeconds() - - updateLabel() - } - - func updateTimer() { - seconds -= 1 - loggedSeconds += 1 - - if(seconds <= 0) { - restartTimer(defaultSeconds) - - let defaults = NSUserDefaults.standardUserDefaults() - if(defaults.objectForKey("playAudioWhenTimerStops") != nil) { - let playAudioWhenTimerStops = defaults.boolForKey("playAudioWhenTimerStops") - if(playAudioWhenTimerStops) { - audioPlayerStart() - } - } else { - audioPlayerStart() - } - } - - updateLabel() - } - - /// - /// Play Audio. - /// - func audioPlayerStart() { - let alertSound = NSURL(fileURLWithPath: NSBundle - .mainBundle() - .pathForResource("finished", ofType: "mp3")!) - - do { - try AVAudioSession.sharedInstance().setActive(true) - - audioPlayer = try AVAudioPlayer(contentsOfURL: alertSound, fileTypeHint: nil) - audioPlayer?.delegate = self - audioPlayer?.prepareToPlay() - audioPlayer?.play() - } catch { - print("AVAudioSession errors.") - } - } - - func logSeconds() { - if let current = current { - if (loggedSeconds > 1 && current.isTimed()) { - let realm = RepositoryStream.sharedInstance.getRealm() - let repositoryRoutine = RepositoryStream.sharedInstance.getRepositoryRoutineForToday() - - if let repositoryExercise = repositoryRoutine.exercises.filter({ - $0.exerciseId == current.exerciseId - }).first { - let sets = repositoryExercise.sets - - try! realm.write { - if (sets.count == 1 && sets[0].seconds == 0) { - sets[0].seconds = loggedSeconds - - showNotification(loggedSeconds) - } else if (sets.count >= 1 && sets.count < 9) { - let repositorySet = RepositorySet() - - repositorySet.exercise = repositoryExercise - repositorySet.isTimed = true - repositorySet.seconds = loggedSeconds - - sets.append(repositorySet) - - repositoryRoutine.lastUpdatedTime = NSDate() - - showNotification(loggedSeconds) - } - - realm.add(repositoryRoutine, update: true) - } - } - } - - } - - loggedSeconds = 0 - } - - /// - /// Notify others that audio has finished playing so they can resume (e.g. Music Player like iTunes or Spotify). - /// - func audioPlayerDidFinishPlaying(player: AVAudioPlayer, successfully flag: Bool) { - do { - try AVAudioSession.sharedInstance().setActive(false, withOptions: - AVAudioSessionSetActiveOptions.NotifyOthersOnDeactivation) - } catch { - print("AVAudioSession errors.") - } - } - - /// - /// Print label to the screen. - /// - func updateLabel() { - let (_, m, s) = secondsToHoursMinutesSeconds(seconds) - - timerMinutesButton.setTitle(printTimerValue(m), forState: UIControlState.Normal) - timerButton.setTitle(printTimerValue(s), forState: UIControlState.Normal) - } - - /// - /// Allows to format timer value e.g. 1 as 01 - /// - func printTimerValue(value: Int) -> String { - if(value > 9) { - return String(value) - } else { - return "0" + String(value) - } - } - - /// - /// Converts value in seconds to hours, minutes and seconds. - /// - func secondsToHoursMinutesSeconds (seconds : Int) -> (Int, Int, Int) { - return (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60) - } -} \ No newline at end of file diff --git a/BodyweightFitness/Controller/WeightedViewController.swift b/BodyweightFitness/Controller/WeightedViewController.swift new file mode 100644 index 0000000..cbd2b71 --- /dev/null +++ b/BodyweightFitness/Controller/WeightedViewController.swift @@ -0,0 +1,179 @@ +import UIKit + +class WeightedViewController: UIViewController { + @IBOutlet var previousButton: UIButton! + @IBOutlet var nextButton: UIButton! + @IBOutlet var logButton: UIButton! + + @IBOutlet var sets: UILabel! + @IBOutlet var reps: UIButton! + + var numberOfReps: Int = 5 + var rootViewController: RootViewController? = nil + var current: Exercise? = nil + + init() { + super.init(nibName: "WeightedView", bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + self.updateLabels() + } + + func changeExercise(currentExercise: Exercise) { + self.current = currentExercise + + self.numberOfReps = PersistenceManager.getNumberOfReps(currentExercise.id) + + self.updateLabels() + + if let _ = self.current?.previous { + self.previousButton.hidden = false + } else { + self.previousButton.hidden = true + } + + if let _ = self.current?.next { + self.nextButton.hidden = false + } else { + self.nextButton.hidden = true + } + } + + func updateLabels() { + if let current = current { + PersistenceManager.storeNumberOfReps(current.id, numberOfReps: self.numberOfReps) + } + + self.sets.text = self.printSets() + self.reps.setTitle(printValue(self.numberOfReps), forState: .Normal) + } + + func printValue(value: Int) -> String { + if(value > 9) { + return String(value) + } else { + return "0" + String(value) + } + } + + func showNotification(set: Int, reps: Int) { + let notification = CWStatusBarNotification() + + notification.notificationLabelFont = UIFont.boldSystemFontOfSize(17) + notification.notificationLabelBackgroundColor = UIColor.primary() + notification.notificationLabelTextColor = UIColor.primaryDark() + + notification.notificationStyle = .NavigationBarNotification + notification.notificationAnimationInStyle = .Top + notification.notificationAnimationOutStyle = .Top + + notification.displayNotificationWithMessage("Logged Set \(set) - \(reps) reps", forDuration: 2.0) + + self.updateLabels() + } + + func printSets() -> String { + var numberOfSets = 0 + var isEmpty = false + + let asString = NSMutableString() + + if let current = self.rootViewController?.current { + let repositoryRoutine = RepositoryStream.sharedInstance.getRepositoryRoutineForToday() + + if let repositoryExercise = repositoryRoutine.exercises.filter({ + $0.exerciseId == current.exerciseId + }).first { + for set in repositoryExercise.sets { + if (repositoryExercise.sets.count == 1 && set.reps == 0) { + isEmpty = true + } + + asString.appendString("\(set.reps)-") + + numberOfSets += 1 + } + + asString.appendString("X") + } + } + + if (isEmpty) { + return "First Set" + } else if (numberOfSets >= 9) { + return "Move on" + } else if (numberOfSets >= 5) { + return "Set \(numberOfSets + 1)" + } + + return asString as String + } + + @IBAction func previousButtonClicked(sender: AnyObject) { + self.rootViewController?.previousButtonClicked(sender) + } + + @IBAction func nextButtonClicked(sender: AnyObject) { + self.rootViewController?.nextButtonClicked(sender) + } + + @IBAction func increaseRepsClicked(sender: AnyObject) { + if self.numberOfReps < 25 { + self.numberOfReps += 1 + + self.updateLabels() + } + } + + @IBAction func decreaseRepsClicked(sender: AnyObject) { + if self.numberOfReps > 1 { + self.numberOfReps -= 1 + + self.updateLabels() + } + } + + @IBAction func logReps(sender: AnyObject) { + if let current = self.rootViewController?.current { + if (self.numberOfReps >= 1 && self.numberOfReps <= 25 && !current.isTimed()) { + let realm = RepositoryStream.sharedInstance.getRealm() + let repositoryRoutine = RepositoryStream.sharedInstance.getRepositoryRoutineForToday() + + if let repositoryExercise = repositoryRoutine.exercises.filter({ + $0.exerciseId == current.exerciseId + }).first { + let sets = repositoryExercise.sets + + try! realm.write { + if (sets.count == 1 && sets[0].reps == 0) { + sets[0].reps = self.numberOfReps + + showNotification(1, reps: self.numberOfReps) + } else if (sets.count >= 1 && sets.count < 9) { + let repositorySet = RepositorySet() + + repositorySet.exercise = repositoryExercise + repositorySet.isTimed = false + repositorySet.reps = self.numberOfReps + + sets.append(repositorySet) + + repositoryRoutine.lastUpdatedTime = NSDate() + } + + realm.add(repositoryRoutine, update: true) + + self.showNotification(sets.count, reps: self.numberOfReps) + } + } + } + } + } +} \ No newline at end of file diff --git a/CalendarViewController.swift b/BodyweightFitness/Controller/WorkoutLogViewController.swift similarity index 77% rename from CalendarViewController.swift rename to BodyweightFitness/Controller/WorkoutLogViewController.swift index dc07f10..3607f1c 100644 --- a/CalendarViewController.swift +++ b/BodyweightFitness/Controller/WorkoutLogViewController.swift @@ -1,101 +1,132 @@ -import Foundation import UIKit import RealmSwift -class CalendarViewController: UIViewController, - CVCalendarViewDelegate, - CVCalendarMenuViewDelegate, - CVCalendarViewAppearanceDelegate, - UITableViewDataSource, - UITableViewDelegate { - +class WorkoutLogViewController: UIViewController, + CVCalendarViewDelegate, + CVCalendarMenuViewDelegate, + CVCalendarViewAppearanceDelegate, + UITableViewDataSource, + UITableViewDelegate { + @IBOutlet weak var backgroundView: UIView! - @IBOutlet weak var bottomView: UIView! - + @IBOutlet weak var calendarView: CVCalendarView! @IBOutlet weak var menuView: CVCalendarMenuView! - + @IBOutlet var tableView: UITableView! - + var date: NSDate? = NSDate() var routines: Results? - + + init() { + super.init(nibName: "WorkoutLogView", bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + override func viewDidLoad() { - super.viewDidLoad() - self.setNavigationBar() + + let menuItem = UIBarButtonItem( + image: UIImage(named: "menu"), + landscapeImagePhone: nil, + style: .Plain, + target: self, + action: #selector(dismiss)) + + menuItem.tintColor = UIColor.primaryDark() + + let calendarItem = UIBarButtonItem( + image: UIImage(named: "calendar"), + landscapeImagePhone: nil, + style: .Plain, + target: self, + action: #selector(toggleCurrentDayView)) + + calendarItem.tintColor = UIColor.primaryDark() + + self.navigationItem.leftBarButtonItem = menuItem + self.navigationItem.rightBarButtonItem = calendarItem + + self.navigationItem.title = CVDate(date: date!).commonDescription + // add the bottom border to the view let border = CALayer() let width = CGFloat(0.5) - + border.borderColor = UIColor(red: 70.0/255.0, green: 70.0/255.0, blue: 80.0/255.0, alpha: 1.0).CGColor border.frame = CGRect( - x: 0, - y: self.backgroundView.frame.size.height - width, - width: self.backgroundView.frame.size.width, - height: self.backgroundView.frame.size.height) - + x: 0, + y: self.backgroundView.frame.size.height - width, + width: self.backgroundView.frame.size.width, + height: self.backgroundView.frame.size.height) + border.borderWidth = width - + self.backgroundView.layer.addSublayer(border) self.backgroundView.layer.masksToBounds = true - + self.calendarView.delegate = self self.calendarView.appearance.delegate = self self.menuView.delegate = self - - self.navigationItem.title = CVDate(date: date!).commonDescription - + self.tableView.registerNib( - UINib(nibName: "CalendarSectionViewCell", bundle: nil), - forCellReuseIdentifier: "CalendarSectionViewCell") - + UINib(nibName: "WorkoutLogSectionCell", bundle: nil), + forCellReuseIdentifier: "WorkoutLogSectionCell") + self.tableView.registerNib( - UINib(nibName: "CalendarCardViewCell", bundle: nil), - forCellReuseIdentifier: "CalendarCardViewCell") - + UINib(nibName: "WorkoutLogCardCell", bundle: nil), + forCellReuseIdentifier: "WorkoutLogCardCell") + tableView.delegate = self tableView.dataSource = self } + + func dismiss(sender: UIBarButtonItem) { + self.sideNavigationController?.toggleLeftView() + } + func toggleCurrentDayView(sender: UIBarButtonItem) { + self.calendarView.toggleCurrentDayView() + } + override func viewDidAppear(animated: Bool) { super.viewDidAppear(animated) - + self.showOrHideCardViewForDate(date!) self.calendarView.contentController.refreshPresentedMonth() } - + override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() - + if UIDevice.currentDevice().userInterfaceIdiom == .Pad { let weekContentViewController = self.calendarView.contentController as! CVCalendarWeekContentViewController - + for (_, weekView) in weekContentViewController.weekViews { for dayView in weekView.dayViews { dayView.setDeselectedWithClearing(true) dayView.selectionView = nil } } - + self.calendarView.validated = false } - + self.calendarView.commitCalendarViewUpdate() self.menuView.commitMenuViewUpdate() - + if UIDevice.currentDevice().userInterfaceIdiom == .Pad { let weekContentViewController = self.calendarView.contentController as! CVCalendarWeekContentViewController - + for (_, weekView) in weekContentViewController.weekViews { for dayView in weekView.dayViews { - let order = NSCalendar.currentCalendar().compareDate( - date!, - toDate: dayView.date.date, - toUnitGranularity: .Day) - + let order = NSCalendar.currentCalendar().compareDate(date!, toDate: dayView.date.date, toUnitGranularity: .Day) + if (order == .OrderedSame) { dayView.setSelectedWithType(.Single) } @@ -103,71 +134,71 @@ class CalendarViewController: UIViewController, } } } - + func showOrHideCardViewForDate(date: NSDate) { self.date = date - + let routines = RepositoryStream.sharedInstance.getRoutinesForDate(date) if (routines.count > 0) { self.routines = routines self.tableView?.backgroundView = nil } else { let label = UILabel(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: tableView.bounds.size.height)) - + label.text = "When you log a workout, you'll see it here." label.font = UIFont(name: "Helvetica Neue", size: 15) label.textAlignment = .Center label.sizeToFit() - + self.routines = nil self.tableView?.backgroundView = label } self.tableView.reloadData() } - + func didSelectDayView(dayView: DayView, animationDidFinish: Bool) { self.showOrHideCardViewForDate(dayView.date.date) } - + func presentedDateUpdated(date: CVDate) { self.navigationItem.title = date.commonDescription } - + func presentationMode() -> CalendarMode { return .WeekView } - + func firstWeekday() -> Weekday { return .Monday } - + func shouldShowWeekdaysOut() -> Bool { return false } - + func shouldAnimateResizing() -> Bool { return false } - + func dotMarker(shouldMoveOnHighlightingOnDayView dayView: DayView) -> Bool { return false } - + func dotMarker(shouldShowOnDayView dayView: DayView) -> Bool { let routines = RepositoryStream.sharedInstance.getRoutinesForDate(dayView.date.date) - + return (routines.count > 0) } - + func dotMarker(colorOnDayView dayView: DayView) -> [UIColor] { return [UIColor.whiteColor()] } - + func dayLabelWeekdayOutTextColor() -> UIColor { return UIColor.whiteColor() } - + func dayLabelWeekdaySelectedBackgroundColor() -> UIColor { return UIColor(red:0, green:0.27, blue:0.24, alpha:1) } @@ -175,23 +206,23 @@ class CalendarViewController: UIViewController, func dayLabelPresentWeekdaySelectedBackgroundColor() -> UIColor { return UIColor.whiteColor() } - + func dayLabelPresentWeekdaySelectedBackgroundAlpha() -> CGFloat { return 1 } - + func dayLabelPresentWeekdaySelectedTextColor() -> UIColor { return UIColor.blackColor() } - + func dayLabelPresentWeekdayTextColor() -> UIColor { return UIColor.blackColor() } - + func dayOfWeekTextColor() -> UIColor { return UIColor(red:0, green: 0.27, blue: 0.24, alpha: 1) } - + func numberOfSectionsInTableView(tableView: UITableView) -> Int { if let _ = self.routines { return 1 @@ -199,7 +230,7 @@ class CalendarViewController: UIViewController, return 0 } } - + func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { if let routines = self.routines { return routines.count @@ -207,58 +238,49 @@ class CalendarViewController: UIViewController, return 0 } } - + func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 44 } - + func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { if (indexPath.row == 0) { return 166 } - + return 166 } - + func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let cell = tableView.dequeueReusableCellWithIdentifier( - "CalendarSectionViewCell") as! CalendarSectionViewCell - + "WorkoutLogSectionCell") as! WorkoutLogSectionCell + cell.title.text = "Workout Log" - + cell.backgroundColor = UIColor(red:0.88, green:0.88, blue:0.88, alpha:1) cell.contentView.backgroundColor = UIColor(red:0.88, green:0.88, blue:0.88, alpha:1) - + return cell - + } - + func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCellWithIdentifier( - "CalendarCardViewCell", - forIndexPath: indexPath) as! CalendarCardViewCell - + "WorkoutLogCardCell", + forIndexPath: indexPath) as! WorkoutLogCardCell + if let routines = self.routines { let repositoryRoutine = routines[indexPath.row] - + cell.parentController = self cell.date = date - + cell.title.text = repositoryRoutine.title cell.subtitle.text = repositoryRoutine.subtitle - + cell.repositoryRoutine = repositoryRoutine } return cell } - - @IBAction func onClickNavigationItem(sender: AnyObject) { - self.sideNavigationController?.toggleLeftView() - } - - - @IBAction func onClickNavigationCalendar(sender: AnyObject) { - self.calendarView.toggleCurrentDayView() - } -} +} \ No newline at end of file diff --git a/Extensions.swift b/BodyweightFitness/Extensions.swift similarity index 62% rename from Extensions.swift rename to BodyweightFitness/Extensions.swift index 434423b..45678f8 100644 --- a/Extensions.swift +++ b/BodyweightFitness/Extensions.swift @@ -30,6 +30,44 @@ extension UIViewController { } extension UIViewController { + func alpha(direction: Direction, color: UIColor = UIColor.blackColor(), alpha: CGFloat = 0.5, speed: Double = 0.5) { + switch direction { + case .In: + let frame = CGRectMake(0, -20, view.frame.width, view.frame.height + 20) + let dimView = UIView(frame: frame) + + dimView.backgroundColor = color + dimView.alpha = 0.0 + + view.addSubview(dimView) + + dimView.translatesAutoresizingMaskIntoConstraints = false + + view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat( + "|[dimView]|", + options: [], + metrics: nil, + views: ["dimView": dimView])) + + view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat( + "V:|[dimView]|", + options: [], + metrics: nil, + views: ["dimView": dimView])) + + UIView.animateWithDuration(speed) { () -> Void in + dimView.alpha = alpha + } + + case .Out: + UIView.animateWithDuration(speed, animations: { () -> Void in + self.view.subviews.last?.alpha = alpha ?? 0 + }, completion: { (complete) -> Void in + self.view.subviews.last?.removeFromSuperview() + }) + } + } + func dim(direction: Direction, color: UIColor = UIColor.blackColor(), alpha: CGFloat = 0.0, speed: Double = 0.0) { switch direction { case .In: diff --git a/BodyweightFitness/Images.xcassets/check.imageset/Contents.json b/BodyweightFitness/Images.xcassets/check.imageset/Contents.json new file mode 100644 index 0000000..9095266 --- /dev/null +++ b/BodyweightFitness/Images.xcassets/check.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Edit Filled-22.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "Edit Filled-44.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "Edit Filled-66.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/BodyweightFitness/Images.xcassets/check.imageset/Edit Filled-22.png b/BodyweightFitness/Images.xcassets/check.imageset/Edit Filled-22.png new file mode 100644 index 0000000..060b66e Binary files /dev/null and b/BodyweightFitness/Images.xcassets/check.imageset/Edit Filled-22.png differ diff --git a/BodyweightFitness/Images.xcassets/check.imageset/Edit Filled-44.png b/BodyweightFitness/Images.xcassets/check.imageset/Edit Filled-44.png new file mode 100644 index 0000000..4db1e46 Binary files /dev/null and b/BodyweightFitness/Images.xcassets/check.imageset/Edit Filled-44.png differ diff --git a/BodyweightFitness/Images.xcassets/check.imageset/Edit Filled-66.png b/BodyweightFitness/Images.xcassets/check.imageset/Edit Filled-66.png new file mode 100644 index 0000000..2d6e08c Binary files /dev/null and b/BodyweightFitness/Images.xcassets/check.imageset/Edit Filled-66.png differ diff --git a/BodyweightFitness/Images.xcassets/minus.imageset/Contents.json b/BodyweightFitness/Images.xcassets/minus.imageset/Contents.json new file mode 100644 index 0000000..56e4832 --- /dev/null +++ b/BodyweightFitness/Images.xcassets/minus.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "Minus Math -22.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "Minus Math -44.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "Minus Math -66.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/BodyweightFitness/Images.xcassets/minus.imageset/Minus Math -22.png b/BodyweightFitness/Images.xcassets/minus.imageset/Minus Math -22.png new file mode 100644 index 0000000..6eec865 Binary files /dev/null and b/BodyweightFitness/Images.xcassets/minus.imageset/Minus Math -22.png differ diff --git a/BodyweightFitness/Images.xcassets/minus.imageset/Minus Math -44.png b/BodyweightFitness/Images.xcassets/minus.imageset/Minus Math -44.png new file mode 100644 index 0000000..968fc94 Binary files /dev/null and b/BodyweightFitness/Images.xcassets/minus.imageset/Minus Math -44.png differ diff --git a/BodyweightFitness/Images.xcassets/minus.imageset/Minus Math -66.png b/BodyweightFitness/Images.xcassets/minus.imageset/Minus Math -66.png new file mode 100644 index 0000000..9de7e29 Binary files /dev/null and b/BodyweightFitness/Images.xcassets/minus.imageset/Minus Math -66.png differ diff --git a/RepositoryCategory.swift b/BodyweightFitness/Model/RepositoryCategory.swift similarity index 100% rename from RepositoryCategory.swift rename to BodyweightFitness/Model/RepositoryCategory.swift diff --git a/RepositoryExercise.swift b/BodyweightFitness/Model/RepositoryExercise.swift similarity index 100% rename from RepositoryExercise.swift rename to BodyweightFitness/Model/RepositoryExercise.swift diff --git a/RepositoryRoutine.swift b/BodyweightFitness/Model/RepositoryRoutine.swift similarity index 100% rename from RepositoryRoutine.swift rename to BodyweightFitness/Model/RepositoryRoutine.swift diff --git a/RepositorySection.swift b/BodyweightFitness/Model/RepositorySection.swift similarity index 100% rename from RepositorySection.swift rename to BodyweightFitness/Model/RepositorySection.swift diff --git a/RepositorySet.swift b/BodyweightFitness/Model/RepositorySet.swift similarity index 100% rename from RepositorySet.swift rename to BodyweightFitness/Model/RepositorySet.swift diff --git a/BodyweightFitness/Model/Routine.swift b/BodyweightFitness/Model/Routine.swift index b99daf4..b644bb4 100644 --- a/BodyweightFitness/Model/Routine.swift +++ b/BodyweightFitness/Model/Routine.swift @@ -104,12 +104,19 @@ class Routine { var linkedExercises: NSMutableArray = [] var linkedRoutine: NSMutableArray = [] - /// - /// Parse JSON file. - /// init(dictionary: Dictionary = Dictionary()) { let json = JSON(data: loadRoutineFromFile()) + self.build(json, dictionary: dictionary) + } + + init(fileName: String) { + let json = JSON(data: loadRoutineFromFile(fileName)) + + self.build(json) + } + + func build(json: JSON, dictionary: Dictionary = Dictionary()) { var currentCategory: Category? var currentSection: Section? var currentExercise: Exercise? @@ -149,7 +156,7 @@ class Routine { desc: item["description"].stringValue, youTubeId: item["youTubeId"].stringValue, defaultSet: item["defaultSet"].stringValue) - + exercise.category = currentCategory exercise.section = currentSection @@ -175,7 +182,7 @@ class Routine { currentSection?.currentExercise = exercise } - + } } else { linkedExercises.addObject(exercise) @@ -191,9 +198,6 @@ class Routine { } } - /// - /// Returns section mode from string. - /// func getMode(mode: String) -> SectionMode { if(mode == "pick") { return SectionMode.Pick @@ -204,17 +208,10 @@ class Routine { } } - /// - /// Returns first exercise in the routine. - /// All exercises are linked together. - /// func getFirstExercise() -> Exercise { return linkedExercises[0] as! Exercise } - - /// - /// Set progression in given section. - /// + func setProgression(exercise: Exercise) { let currentSectionExercise = exercise.section?.currentExercise @@ -227,11 +224,8 @@ class Routine { exercise.section?.currentExercise = exercise } - /// - /// Load JSON from file. - /// - func loadRoutineFromFile() -> NSData { - let fileRoot = NSBundle.mainBundle().pathForResource("Routine", ofType: "json")! + func loadRoutineFromFile(fileName: String = "Routine") -> NSData { + let fileRoot = NSBundle.mainBundle().pathForResource(fileName, ofType: "json")! do { return try NSData(contentsOfFile: fileRoot, options: .DataReadingMappedIfSafe) diff --git a/BodyweightFitness/Resources/Gifs/band_chest_flies.gif b/BodyweightFitness/Resources/Gifs/band_chest_flies.gif new file mode 100644 index 0000000..59f342a Binary files /dev/null and b/BodyweightFitness/Resources/Gifs/band_chest_flies.gif differ diff --git a/BodyweightFitness/Resources/Gifs/band_pull_downs.gif b/BodyweightFitness/Resources/Gifs/band_pull_downs.gif new file mode 100644 index 0000000..3c5f7e6 Binary files /dev/null and b/BodyweightFitness/Resources/Gifs/band_pull_downs.gif differ diff --git a/BodyweightFitness/Resources/Gifs/full_body_circles.gif b/BodyweightFitness/Resources/Gifs/full_body_circles.gif deleted file mode 100755 index 12a86a7..0000000 Binary files a/BodyweightFitness/Resources/Gifs/full_body_circles.gif and /dev/null differ diff --git a/ring_wide_pushup.gif b/BodyweightFitness/Resources/Gifs/ring_wide_pushup.gif similarity index 100% rename from ring_wide_pushup.gif rename to BodyweightFitness/Resources/Gifs/ring_wide_pushup.gif diff --git a/BodyweightFitness/Resources/Gifs/shoulder_rolls.gif b/BodyweightFitness/Resources/Gifs/shoulder_rolls.gif new file mode 100644 index 0000000..f75f6c3 Binary files /dev/null and b/BodyweightFitness/Resources/Gifs/shoulder_rolls.gif differ diff --git a/BodyweightFitness/Resources/Routine.json b/BodyweightFitness/Resources/Routine.json index 0b6ed25..4e80103 100644 --- a/BodyweightFitness/Resources/Routine.json +++ b/BodyweightFitness/Resources/Routine.json @@ -1,594 +1,614 @@ { - "routine":[ - { - "categoryId":"category0", - "title":"Warmup", - "type":"category" - }, - { - "sectionId":"section0", - "title":"Dynamic Stretches", - "description":"Do all, 1x(5-10)", - "type":"section", - "mode":"all" - }, - { - "exerciseId":"exercise0", - "id":"wall_extensions", - "title":"Wall Extensions", - "description":"1x(5-10)", - "type":"exercise", - "youTubeId":"d6V2Exzb324", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise1", - "id":"band_dislocates", - "title":"Band Dislocates", - "description":"1x(5-10)", - "type":"exercise", - "youTubeId":"WyW5jGGxoZk", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise2", - "id":"cat_camel", - "title":"Cat\/Camel Bends", - "description":"1x(5-10)", - "type":"exercise", - "youTubeId":"K9bK0BwKFjs", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise3", - "id":"scapular_shrugs", - "title":"Scapular Shrugs", - "description":"1x(5-10)", - "type":"exercise", - "youTubeId":"akgQbxhrhOc", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise4", - "id":"full_body_circles", - "title":"Full Body Circles", - "description":"1x(5-10)", - "type":"exercise", - "youTubeId":"yRigKuEou7k", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise5", - "id":"leg_swings", - "title":"Front and Side Leg Swings", - "description":"1x(5-10)", - "type":"exercise", - "youTubeId":"4aoUZEZFJF8", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise6", - "id":"wrist_progression", - "title":"Wrist Mobility Exercises", - "description":"1x(5-10)", - "type":"exercise", - "youTubeId":"HU5UCh_E6Ns", - "defaultSet":"weighted" - }, - { - "sectionId":"section1", - "title":"Bodyline Drills", - "description":"Do all, 1x(10-60s) hold each", - "type":"section", - "mode":"all" - }, - { - "exerciseId":"exercise7", - "id":"plank", - "title":"Plank", - "description":"1x(10-60s) hold", - "type":"exercise", - "youTubeId":"PLu6k-uKOJ0", - "defaultSet":"timed" - }, - { - "exerciseId":"exercise8", - "id":"side_plank", - "title":"Side Plank (Both sides)", - "description":"1x(10-60s) hold", - "type":"exercise", - "youTubeId":"xIFWxQgFMiE", - "defaultSet":"timed" - }, - { - "exerciseId":"exercise9", - "id":"reverse_plank", - "title":"Reverse Plank", - "description":"1x(10-60s) hold", - "type":"exercise", - "youTubeId":"1s1bPYBPERU", - "defaultSet":"timed" - }, - { - "exerciseId":"exercise10", - "id":"hollow_hold", - "title":"Hollow Hold", - "description":"1x(10-60s) hold", - "type":"exercise", - "youTubeId":"wrzjVTK2brk", - "defaultSet":"timed" - }, - { - "exerciseId":"exercise11", - "id":"arch", - "title":"Arch", - "description":"1x(10-60s) hold", - "type":"exercise", - "youTubeId":"wrzjVTK2brk", - "defaultSet":"timed" - }, - { - "sectionId":"section2", - "title":"Activity", - "description":"Pick one, 1x(10-20)", - "type":"section", - "mode":"pick" - }, - { - "exerciseId":"exercise12", - "id":"squat_jumps", - "title":"Squat Jumps", - "description":"1x(10-20)", - "type":"exercise", - "youTubeId":"CVaEhXotL7M", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise13", - "id":"burpee", - "title":"Burpees", - "description":"1x(10-20)", - "type":"exercise", - "youTubeId":"41knz-ZUiBU", - "defaultSet":"weighted" - }, - { - "categoryId":"category1", - "title":"Skill Work", - "type":"category" - }, - { - "sectionId":"section3", - "title":"Handstand", - "description":"5 min", - "type":"section", - "mode":"levels" - }, - { - "exerciseId":"exercise14", - "id":"wall_plank", - "level":"Level 1", - "title":"Wall Plank", - "description":"5 min", - "type":"exercise", - "youTubeId":"6jm4R3K4sJA", - "defaultSet":"timed" - }, - { - "exerciseId":"exercise15", - "id":"wall_handstand", - "level":"Level 2", - "title":"Stomach-to-Wall Handstand", - "description":"5 min", - "type":"exercise", - "youTubeId":"dRycbwdcz7Y", - "defaultSet":"timed" - }, - { - "exerciseId":"exercise16", - "id":"freestanding_handstand", - "level":"Level 3", - "title":"Freestanding Handstand", - "description":"5 min", - "type":"exercise", - "youTubeId":"Y3FSeSecjKA", - "defaultSet":"timed" - }, - { - "sectionId":"section4", - "title":"Support Practice", - "description":"2-3 min", - "type":"section", - "mode":"levels" - }, - { - "exerciseId":"exercise17", - "id":"parallel_bar_hold", - "level":"Level 1", - "title":"Parallel Bar support", - "description":"2-3 min", - "type":"exercise", - "youTubeId":"Zv87Teu51tQ", - "defaultSet":"timed" - }, - { - "exerciseId":"exercise18", - "id":"ring_support", - "level":"Level 2", - "title":"Ring Support", - "description":"2-3 min", - "type":"exercise", - "youTubeId":"V3IkFK5lvRw", - "defaultSet":"timed" - }, - { - "exerciseId":"exercise19", - "id":"rings_turned_out_support", - "level":"Level 3", - "title":"Rings Turned Out Support Hold", - "description":"2-3 min", - "type":"exercise", - "youTubeId":"8gmyhBScTLk", - "defaultSet":"timed" - }, - { - "categoryId":"category2", - "title":"Strength Work", - "type":"category" - }, - { - "sectionId":"section5", - "title":"Pullup Progression", - "description":"3x(5-8)", - "type":"section", - "mode":"levels", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise20", - "id":"negative_pullup", - "level":"Level 1", - "title":"Negative Pullups", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"y5sqSwcRZzo", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise21", - "id":"pullup", - "level":"Level 2", - "title":"Pull Up", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"RsnbDcsZbpk", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise22", - "id":"lsit_pullup", - "level":"Level 3", - "title":"L-sit Pull Up", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"quFBLtkxMRM", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise23", - "id":"pullover", - "level":"Level 4", - "title":"Pull Over", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"saLtuweg8As", - "defaultSet":"weighted" - }, - { - "sectionId":"section6", - "title":"Dipping Progression", - "description":"3x(5-8)", - "type":"section", - "mode":"levels" - }, - { - "exerciseId":"exercise24", - "id":"parallel_bar_dips", - "level":"Level 1", - "title":"Parallel Bar Dips", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"_3RaUMKcGQI", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise25", - "id":"ring_dips", - "level":"Level 2", - "title":"Ring Dips", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"cPFmMwC62d8", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise26", - "id":"l_ring_dips", - "level":"Level 3", - "title":"Ring Dips in L-sit", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"K-fNLVAstcw", - "defaultSet":"weighted" - }, - { - "sectionId":"section7", - "title":"Squat Progression", - "description":"3x(5-8)", - "type":"section", - "mode":"levels" - }, - { - "exerciseId":"exercise27", - "id":"assisted_squat", - "level":"Level 1", - "title":"Assisted Bodyweight Squat", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"OuR_Fp7AB0c", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise28", - "id":"bodyweight_squat", - "level":"Level 2", - "title":"Bodyweight Squat", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"AkQbbDGMzJk", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise29", - "id":"deep_stepup", - "level":"Level 3", - "title":"Deep Step-up", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"487aR3A7HvM", - "defaultSet":"weighted" - }, - { - "sectionId":"section8", - "title":"L-sit Progression", - "description":"3x(10-30s)", - "type":"section", - "mode":"levels" - }, - { - "exerciseId":"exercise30", - "id":"floor_l_sit", - "level":"Level 1", - "title":"Foot-supported L-sit", - "description":"3x(10-30s)", - "type":"exercise", - "youTubeId":"IUZJoSP66HI", - "defaultSet":"timed" - }, - { - "exerciseId":"exercise31", - "id":"one_foot_l_sit", - "level":"Level 2", - "title":"One-Leg Foot Supported L-sit", - "description":"3x(10-30s)", - "type":"exercise", - "youTubeId":"IUZJoSP66HI", - "defaultSet":"timed" - }, - { - "exerciseId":"exercise32", - "id":"tuck_l_sit", - "level":"Level 3", - "title":"Tuck L-sit", - "description":"3x(10-30s)", - "type":"exercise", - "youTubeId":"IUZJoSP66HI", - "defaultSet":"timed" - }, - { - "exerciseId":"exercise33", - "id":"l_sit", - "level":"Level 4", - "title":"L-sit", - "description":"3x(10-30s)", - "type":"exercise", - "youTubeId":"ek76IXnE9tE", - "defaultSet":"timed" - }, - { - "sectionId":"section9", - "title":"Pushing", - "description":"3x(5-8)", - "type":"section", - "mode":"levels" - }, - { - "exerciseId":"exercise34", - "id":"wall_pushup", - "level":"Level 1", - "title":"Wall Pushup", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"a6YHbXD2XlU", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise35", - "id":"incline_pushup", - "level":"Level 2", - "title":"Incline Pushup", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"4dF1DOWzf20", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise36", - "id":"pushup", - "level":"Level 3", - "title":"Pushup", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"4dF1DOWzf20", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise37", - "id":"diamond_pushup", - "level":"Level 4", - "title":"Diamond Pushup", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"s8Ft6xyN5fw", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise38", - "id":"ring_wide_pushup", - "level":"Level 5", - "title":"Rings Wide Pushups", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"jbQyi9xshOU", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise39", - "id":"ring_pushup", - "level":"Level 6", - "title":"Rings Pushups", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"jbQyi9xshOU", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise40", - "id":"rings_turned_out_pushup", - "level":"Level 7", - "title":"Rings Turned Out Pushup", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"MrlyEIpe0LI", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise41", - "id":"pseudo_planche_pushup", - "level":"Level 8", - "title":"Rings Turned Out PPPU", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"-kwe1EOiWMY", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise42", - "id":"pseudo_planche", - "level":"Level 5-8", - "title":"Pseudo Planche Push Ups", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"Cdmg0CfMZeo", - "defaultSet":"weighted" - }, - { - "sectionId":"section10", - "title":"Row Progression", - "description":"3x(5-8)", - "type":"section", - "mode":"levels" - }, - { - "exerciseId":"exercise43", - "id":"vertical_row", - "level":"Level 1", - "title":"Vertical Row", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"e5fdh9_kH_Y", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise44", - "id":"incline_row", - "level":"Level 2", - "title":"Incline Row", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"1G28qN9FCKE", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise45", - "id":"horizontal_row", - "level":"Level 3", - "title":"Horizontal Row", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"dvkIaarnf0g", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise46", - "id":"wide_row", - "level":"Level 4", - "title":"Wide Row", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"1yMRvsuk9Xg", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise47", - "id":"tuck_front_lever", - "level":"Level 5", - "title":"Tuck Front Lever", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"tiST0765Sfo", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise48", - "id":"tuck_ice_cream_maker", - "level":"Level 6", - "title":"Tuck Ice Cream Maker", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"AszLwoAvLKg", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise49", - "id":"tuck_front_lever_row", - "level":"Level 7", - "title":"Tuck Front Lever Row", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"F-xEL0Ot0HA", - "defaultSet":"weighted" - }, - { - "exerciseId":"exercise50", - "id":"advanced_tuck_front_lever_row", - "level":"Level 8", - "title":"Advanced Tuck Front Lever Row", - "description":"3x(5-8)", - "type":"exercise", - "youTubeId":"cVdb8oUGKAw", - "defaultSet":"weighted" - } - ] - + "routineId": "routine0", + "title": "Bodyweight Fitness", + "subtitle": "Recommended Routine", + "routine": [ + { + "categoryId": "category0", + "title": "Warmup", + "type": "category" + }, + { + "sectionId": "section0", + "title": "Dynamic Stretches", + "description": "Do all, 5-10 reps each", + "type": "section", + "mode": "all" + }, + { + "exerciseId": "exercise0", + "id": "wall_extensions", + "title": "Wall Extensions", + "description": "1x(5-10)", + "type": "exercise", + "youTubeId": "d6V2Exzb324", + "defaultSet": "weighted" + }, + { + "exerciseId": "01379fb5-80af-474a-90b6-efcebed138d4", + "id": "shoulder_rolls", + "title": "Shoulder Rolls", + "description": "1x(5-10)", + "type": "exercise", + "youTubeId": "H01oGIS1C_g", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise3", + "id": "scapular_shrugs", + "title": "Scapular Shrugs", + "description": "1x(5-10)", + "type": "exercise", + "youTubeId": "akgQbxhrhOc", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise2", + "id": "cat_camel", + "title": "Camel Bends", + "description": "1x(5-10)", + "type": "exercise", + "youTubeId": "K9bK0BwKFjs", + "defaultSet": "weighted" + }, + { + "exerciseId": "084e964d-875b-4fb2-81db-02de9820363c", + "id": "band_pull_downs", + "title": "Straight Arm Overhead Pull Downs", + "description": "1x(5-10)", + "type": "exercise", + "youTubeId": "8lDC4Ri9zAQ&feature=youtu.be&t=4m22s", + "defaultSet": "weighted" + }, + { + "exerciseId": "2589e669-6bc6-4796-a3a5-0b4e32456e92", + "id": "band_chest_flies", + "title": "Straight Arm Chest Flies", + "description": "1x(5-10)", + "type": "exercise", + "youTubeId": "8lDC4Ri9zAQ&feature=youtu.be&t=5m12s", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise1", + "id": "band_dislocates", + "title": "Band Dislocates", + "description": "1x(5-10)", + "type": "exercise", + "youTubeId": "WyW5jGGxoZk", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise5", + "id": "leg_swings", + "title": "Front and Side Leg Swings", + "description": "1x(5-10)", + "type": "exercise", + "youTubeId": "4aoUZEZFJF8", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise6", + "id": "wrist_progression", + "title": "Wrist Mobility Exercises", + "description": "1x(5-10)", + "type": "exercise", + "youTubeId": "HU5UCh_E6Ns", + "defaultSet": "weighted" + }, + { + "sectionId": "section1", + "title": "Bodyline Drills", + "description": "Do all, 10-60s hold each", + "type": "section", + "mode": "all" + }, + { + "exerciseId": "exercise7", + "id": "plank", + "title": "Plank", + "description": "1x(10-60s) hold", + "type": "exercise", + "youTubeId": "PLu6k-uKOJ0", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise8", + "id": "side_plank", + "title": "Side Plank (Both Sides)", + "description": "1x(10-60s) hold", + "type": "exercise", + "youTubeId": "xIFWxQgFMiE", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise9", + "id": "reverse_plank", + "title": "Reverse Plank", + "description": "1x(10-60s) hold", + "type": "exercise", + "youTubeId": "1s1bPYBPERU", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise10", + "id": "hollow_hold", + "title": "Hollow Hold", + "description": "1x(10-60s) hold", + "type": "exercise", + "youTubeId": "wrzjVTK2brk", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise11", + "id": "arch", + "title": "Arch", + "description": "1x(10-60s) hold", + "type": "exercise", + "youTubeId": "wrzjVTK2brk", + "defaultSet": "timed" + }, + { + "sectionId": "section2", + "title": "Activity", + "description": "Pick one, 10-20 reps", + "type": "section", + "mode": "pick" + }, + { + "exerciseId": "exercise12", + "id": "squat_jumps", + "title": "Squat Jumps", + "description": "1x(10-20)", + "type": "exercise", + "youTubeId": "CVaEhXotL7M", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise13", + "id": "burpee", + "title": "Burpees", + "description": "1x(10-20)", + "type": "exercise", + "youTubeId": "41knz-ZUiBU", + "defaultSet": "weighted" + }, + { + "categoryId": "category1", + "title": "Skill Work", + "type": "category" + }, + { + "sectionId": "section3", + "title": "Handstand", + "description": "5 min", + "type": "section", + "mode": "levels" + }, + { + "exerciseId": "exercise14", + "id": "wall_plank", + "level": "Level 1", + "title": "Wall Plank", + "description": "5 min", + "type": "exercise", + "youTubeId": "6jm4R3K4sJA", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise15", + "id": "wall_handstand", + "level": "Level 2", + "title": "Stomach-to-Wall Handstand", + "description": "5 min", + "type": "exercise", + "youTubeId": "dRycbwdcz7Y", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise16", + "id": "freestanding_handstand", + "level": "Level 3", + "title": "Freestanding Handstand", + "description": "5 min", + "type": "exercise", + "youTubeId": "Y3FSeSecjKA", + "defaultSet": "timed" + }, + { + "sectionId": "section4", + "title": "Support Practice", + "description": "2-3 min", + "type": "section", + "mode": "levels" + }, + { + "exerciseId": "exercise17", + "id": "parallel_bar_hold", + "level": "Level 1", + "title": "Parallel Bar Support", + "description": "2-3 min", + "type": "exercise", + "youTubeId": "Zv87Teu51tQ", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise18", + "id": "ring_support", + "level": "Level 2", + "title": "Ring Support", + "description": "2-3 min", + "type": "exercise", + "youTubeId": "V3IkFK5lvRw", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise19", + "id": "rings_turned_out_support", + "level": "Level 3", + "title": "Rings Turned Out Support Hold", + "description": "2-3 min", + "type": "exercise", + "youTubeId": "8gmyhBScTLk", + "defaultSet": "timed" + }, + { + "categoryId": "category2", + "title": "Strength Work", + "type": "category" + }, + { + "sectionId": "section5", + "title": "Pullup Progression", + "description": "3x(5-8)", + "type": "section", + "mode": "levels", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise20", + "id": "negative_pullup", + "level": "Level 1", + "title": "Negative Pullups", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "y5sqSwcRZzo", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise21", + "id": "pullup", + "level": "Level 2", + "title": "Pull Up", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "RsnbDcsZbpk", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise22", + "id": "lsit_pullup", + "level": "Level 3", + "title": "L-sit Pull Up", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "quFBLtkxMRM", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise23", + "id": "pullover", + "level": "Level 4", + "title": "Pull Over", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "saLtuweg8As", + "defaultSet": "weighted" + }, + { + "sectionId": "section6", + "title": "Dipping Progression", + "description": "3x(5-8)", + "type": "section", + "mode": "levels" + }, + { + "exerciseId": "exercise24", + "id": "parallel_bar_dips", + "level": "Level 1", + "title": "Parallel Bar Dips", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "_3RaUMKcGQI", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise25", + "id": "ring_dips", + "level": "Level 2", + "title": "Ring Dips", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "cPFmMwC62d8", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise26", + "id": "l_ring_dips", + "level": "Level 3", + "title": "Ring Dips in L-sit", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "K-fNLVAstcw", + "defaultSet": "weighted" + }, + { + "sectionId": "section7", + "title": "Squat Progression", + "description": "3x(5-8)", + "type": "section", + "mode": "levels" + }, + { + "exerciseId": "exercise27", + "id": "assisted_squat", + "level": "Level 1", + "title": "Assisted Bodyweight Squat", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "OuR_Fp7AB0c", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise28", + "id": "bodyweight_squat", + "level": "Level 2", + "title": "Bodyweight Squat", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "AkQbbDGMzJk", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise29", + "id": "deep_stepup", + "level": "Level 3", + "title": "Deep Step-up", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "487aR3A7HvM", + "defaultSet": "weighted" + }, + { + "sectionId": "section8", + "title": "L-sit Progression", + "description": "3x(10-30s)", + "type": "section", + "mode": "levels" + }, + { + "exerciseId": "exercise30", + "id": "floor_l_sit", + "level": "Level 1", + "title": "Foot-supported L-sit", + "description": "3x(10-30s)", + "type": "exercise", + "youTubeId": "IUZJoSP66HI", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise31", + "id": "one_foot_l_sit", + "level": "Level 2", + "title": "One-Leg Foot Supported L-sit", + "description": "3x(10-30s)", + "type": "exercise", + "youTubeId": "IUZJoSP66HI", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise32", + "id": "tuck_l_sit", + "level": "Level 3", + "title": "Tuck L-sit", + "description": "3x(10-30s)", + "type": "exercise", + "youTubeId": "IUZJoSP66HI", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise33", + "id": "l_sit", + "level": "Level 4", + "title": "L-sit", + "description": "3x(10-30s)", + "type": "exercise", + "youTubeId": "ek76IXnE9tE", + "defaultSet": "timed" + }, + { + "sectionId": "section9", + "title": "Pushing", + "description": "3x(5-8)", + "type": "section", + "mode": "levels" + }, + { + "exerciseId": "exercise34", + "id": "wall_pushup", + "level": "Level 1", + "title": "Wall Pushup", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "a6YHbXD2XlU", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise35", + "id": "incline_pushup", + "level": "Level 2", + "title": "Incline Pushup", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "4dF1DOWzf20", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise36", + "id": "pushup", + "level": "Level 3", + "title": "Pushup", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "4dF1DOWzf20", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise37", + "id": "diamond_pushup", + "level": "Level 4", + "title": "Diamond Pushup", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "s8Ft6xyN5fw", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise38", + "id": "ring_wide_pushup", + "level": "Level 5", + "title": "Rings Wide Pushups", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "jbQyi9xshOU", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise39", + "id": "ring_pushup", + "level": "Level 6", + "title": "Rings Pushups", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "jbQyi9xshOU", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise40", + "id": "rings_turned_out_pushup", + "level": "Level 7", + "title": "Rings Turned Out Pushup", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "MrlyEIpe0LI", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise41", + "id": "pseudo_planche_pushup", + "level": "Level 8", + "title": "Rings Turned Out PPPU", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "-kwe1EOiWMY", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise42", + "id": "pseudo_planche", + "level": "Level 5-8", + "title": "Pseudo Planche Push Ups", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "Cdmg0CfMZeo", + "defaultSet": "weighted" + }, + { + "sectionId": "section10", + "title": "Row Progression", + "description": "3x(5-8)", + "type": "section", + "mode": "levels" + }, + { + "exerciseId": "exercise43", + "id": "vertical_row", + "level": "Level 1", + "title": "Vertical Row", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "e5fdh9_kH_Y", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise44", + "id": "incline_row", + "level": "Level 2", + "title": "Incline Row", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "1G28qN9FCKE", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise45", + "id": "horizontal_row", + "level": "Level 3", + "title": "Horizontal Row", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "dvkIaarnf0g", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise46", + "id": "wide_row", + "level": "Level 4", + "title": "Wide Row", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "1yMRvsuk9Xg", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise47", + "id": "tuck_front_lever", + "level": "Level 5", + "title": "Tuck Front Lever", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "tiST0765Sfo", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise48", + "id": "tuck_ice_cream_maker", + "level": "Level 6", + "title": "Tuck Ice Cream Maker", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "AszLwoAvLKg", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise49", + "id": "tuck_front_lever_row", + "level": "Level 7", + "title": "Tuck Front Lever Row", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "F-xEL0Ot0HA", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise50", + "id": "advanced_tuck_front_lever_row", + "level": "Level 8", + "title": "Advanced Tuck Front Lever Row", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "cVdb8oUGKAw", + "defaultSet": "weighted" + } + ] } \ No newline at end of file diff --git a/BodyweightFitness/Resources/TestRoutine.json b/BodyweightFitness/Resources/TestRoutine.json new file mode 100644 index 0000000..0f51834 --- /dev/null +++ b/BodyweightFitness/Resources/TestRoutine.json @@ -0,0 +1,587 @@ +{ + "routineId": "routine0", + "title": "Bodyweight Fitness", + "subtitle": "Recommended Routine", + "routine": [ + { + "categoryId": "category0", + "title": "Warmup", + "type": "category" + }, + { + "sectionId": "section0", + "title": "Dynamic Stretches", + "description": "Do all, 5-10 reps each", + "type": "section", + "mode": "all" + }, + { + "exerciseId": "exercise0", + "id": "wall_extensions", + "title": "Wall Extensions", + "description": "1x(5-10)", + "type": "exercise", + "youTubeId": "d6V2Exzb324", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise3", + "id": "scapular_shrugs", + "title": "Scapular Shrugs", + "description": "1x(5-10)", + "type": "exercise", + "youTubeId": "akgQbxhrhOc", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise2", + "id": "cat_camel", + "title": "Camel Bends", + "description": "1x(5-10)", + "type": "exercise", + "youTubeId": "K9bK0BwKFjs", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise1", + "id": "band_dislocates", + "title": "Band Dislocates", + "description": "1x(5-10)", + "type": "exercise", + "youTubeId": "WyW5jGGxoZk", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise5", + "id": "leg_swings", + "title": "Front and Side Leg Swings", + "description": "1x(5-10)", + "type": "exercise", + "youTubeId": "4aoUZEZFJF8", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise6", + "id": "wrist_progression", + "title": "Wrist Mobility Exercises", + "description": "1x(5-10)", + "type": "exercise", + "youTubeId": "HU5UCh_E6Ns", + "defaultSet": "weighted" + }, + { + "sectionId": "section1", + "title": "Bodyline Drills", + "description": "Do all, 10-60s hold each", + "type": "section", + "mode": "all" + }, + { + "exerciseId": "exercise7", + "id": "plank", + "title": "Plank", + "description": "1x(10-60s) hold", + "type": "exercise", + "youTubeId": "PLu6k-uKOJ0", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise8", + "id": "side_plank", + "title": "Side Plank (Both Sides)", + "description": "1x(10-60s) hold", + "type": "exercise", + "youTubeId": "xIFWxQgFMiE", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise9", + "id": "reverse_plank", + "title": "Reverse Plank", + "description": "1x(10-60s) hold", + "type": "exercise", + "youTubeId": "1s1bPYBPERU", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise10", + "id": "hollow_hold", + "title": "Hollow Hold", + "description": "1x(10-60s) hold", + "type": "exercise", + "youTubeId": "wrzjVTK2brk", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise11", + "id": "arch", + "title": "Arch", + "description": "1x(10-60s) hold", + "type": "exercise", + "youTubeId": "wrzjVTK2brk", + "defaultSet": "timed" + }, + { + "sectionId": "section2", + "title": "Activity", + "description": "Pick one, 10-20 reps", + "type": "section", + "mode": "pick" + }, + { + "exerciseId": "exercise12", + "id": "squat_jumps", + "title": "Squat Jumps", + "description": "1x(10-20)", + "type": "exercise", + "youTubeId": "CVaEhXotL7M", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise13", + "id": "burpee", + "title": "Burpees", + "description": "1x(10-20)", + "type": "exercise", + "youTubeId": "41knz-ZUiBU", + "defaultSet": "weighted" + }, + { + "categoryId": "category1", + "title": "Skill Work", + "type": "category" + }, + { + "sectionId": "section3", + "title": "Handstand", + "description": "5 min", + "type": "section", + "mode": "levels" + }, + { + "exerciseId": "exercise14", + "id": "wall_plank", + "level": "Level 1", + "title": "Wall Plank", + "description": "5 min", + "type": "exercise", + "youTubeId": "6jm4R3K4sJA", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise15", + "id": "wall_handstand", + "level": "Level 2", + "title": "Stomach-to-Wall Handstand", + "description": "5 min", + "type": "exercise", + "youTubeId": "dRycbwdcz7Y", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise16", + "id": "freestanding_handstand", + "level": "Level 3", + "title": "Freestanding Handstand", + "description": "5 min", + "type": "exercise", + "youTubeId": "Y3FSeSecjKA", + "defaultSet": "timed" + }, + { + "sectionId": "section4", + "title": "Support Practice", + "description": "2-3 min", + "type": "section", + "mode": "levels" + }, + { + "exerciseId": "exercise17", + "id": "parallel_bar_hold", + "level": "Level 1", + "title": "Parallel Bar Support", + "description": "2-3 min", + "type": "exercise", + "youTubeId": "Zv87Teu51tQ", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise18", + "id": "ring_support", + "level": "Level 2", + "title": "Ring Support", + "description": "2-3 min", + "type": "exercise", + "youTubeId": "V3IkFK5lvRw", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise19", + "id": "rings_turned_out_support", + "level": "Level 3", + "title": "Rings Turned Out Support Hold", + "description": "2-3 min", + "type": "exercise", + "youTubeId": "8gmyhBScTLk", + "defaultSet": "timed" + }, + { + "categoryId": "category2", + "title": "Strength Work", + "type": "category" + }, + { + "sectionId": "section5", + "title": "Pullup Progression", + "description": "3x(5-8)", + "type": "section", + "mode": "levels", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise20", + "id": "negative_pullup", + "level": "Level 1", + "title": "Negative Pullups", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "y5sqSwcRZzo", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise21", + "id": "pullup", + "level": "Level 2", + "title": "Pull Up", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "RsnbDcsZbpk", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise22", + "id": "lsit_pullup", + "level": "Level 3", + "title": "L-sit Pull Up", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "quFBLtkxMRM", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise23", + "id": "pullover", + "level": "Level 4", + "title": "Pull Over", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "saLtuweg8As", + "defaultSet": "weighted" + }, + { + "sectionId": "section6", + "title": "Dipping Progression", + "description": "3x(5-8)", + "type": "section", + "mode": "levels" + }, + { + "exerciseId": "exercise24", + "id": "parallel_bar_dips", + "level": "Level 1", + "title": "Parallel Bar Dips", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "_3RaUMKcGQI", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise25", + "id": "ring_dips", + "level": "Level 2", + "title": "Ring Dips", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "cPFmMwC62d8", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise26", + "id": "l_ring_dips", + "level": "Level 3", + "title": "Ring Dips in L-sit", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "K-fNLVAstcw", + "defaultSet": "weighted" + }, + { + "sectionId": "section7", + "title": "Squat Progression", + "description": "3x(5-8)", + "type": "section", + "mode": "levels" + }, + { + "exerciseId": "exercise27", + "id": "assisted_squat", + "level": "Level 1", + "title": "Assisted Bodyweight Squat", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "OuR_Fp7AB0c", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise28", + "id": "bodyweight_squat", + "level": "Level 2", + "title": "Bodyweight Squat", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "AkQbbDGMzJk", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise29", + "id": "deep_stepup", + "level": "Level 3", + "title": "Deep Step-up", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "487aR3A7HvM", + "defaultSet": "weighted" + }, + { + "sectionId": "section8", + "title": "L-sit Progression", + "description": "3x(10-30s)", + "type": "section", + "mode": "levels" + }, + { + "exerciseId": "exercise30", + "id": "floor_l_sit", + "level": "Level 1", + "title": "Foot-supported L-sit", + "description": "3x(10-30s)", + "type": "exercise", + "youTubeId": "IUZJoSP66HI", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise31", + "id": "one_foot_l_sit", + "level": "Level 2", + "title": "One-Leg Foot Supported L-sit", + "description": "3x(10-30s)", + "type": "exercise", + "youTubeId": "IUZJoSP66HI", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise32", + "id": "tuck_l_sit", + "level": "Level 3", + "title": "Tuck L-sit", + "description": "3x(10-30s)", + "type": "exercise", + "youTubeId": "IUZJoSP66HI", + "defaultSet": "timed" + }, + { + "exerciseId": "exercise33", + "id": "l_sit", + "level": "Level 4", + "title": "L-sit", + "description": "3x(10-30s)", + "type": "exercise", + "youTubeId": "ek76IXnE9tE", + "defaultSet": "timed" + }, + { + "sectionId": "section9", + "title": "Pushing", + "description": "3x(5-8)", + "type": "section", + "mode": "levels" + }, + { + "exerciseId": "exercise34", + "id": "wall_pushup", + "level": "Level 1", + "title": "Wall Pushup", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "a6YHbXD2XlU", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise35", + "id": "incline_pushup", + "level": "Level 2", + "title": "Incline Pushup", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "4dF1DOWzf20", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise36", + "id": "pushup", + "level": "Level 3", + "title": "Pushup", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "4dF1DOWzf20", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise37", + "id": "diamond_pushup", + "level": "Level 4", + "title": "Diamond Pushup", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "s8Ft6xyN5fw", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise38", + "id": "ring_wide_pushup", + "level": "Level 5", + "title": "Rings Wide Pushups", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "jbQyi9xshOU", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise39", + "id": "ring_pushup", + "level": "Level 6", + "title": "Rings Pushups", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "jbQyi9xshOU", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise40", + "id": "rings_turned_out_pushup", + "level": "Level 7", + "title": "Rings Turned Out Pushup", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "MrlyEIpe0LI", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise41", + "id": "pseudo_planche_pushup", + "level": "Level 8", + "title": "Rings Turned Out PPPU", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "-kwe1EOiWMY", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise42", + "id": "pseudo_planche", + "level": "Level 5-8", + "title": "Pseudo Planche Push Ups", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "Cdmg0CfMZeo", + "defaultSet": "weighted" + }, + { + "sectionId": "section10", + "title": "Row Progression", + "description": "3x(5-8)", + "type": "section", + "mode": "levels" + }, + { + "exerciseId": "exercise43", + "id": "vertical_row", + "level": "Level 1", + "title": "Vertical Row", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "e5fdh9_kH_Y", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise44", + "id": "incline_row", + "level": "Level 2", + "title": "Incline Row", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "1G28qN9FCKE", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise45", + "id": "horizontal_row", + "level": "Level 3", + "title": "Horizontal Row", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "dvkIaarnf0g", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise46", + "id": "wide_row", + "level": "Level 4", + "title": "Wide Row", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "1yMRvsuk9Xg", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise47", + "id": "tuck_front_lever", + "level": "Level 5", + "title": "Tuck Front Lever", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "tiST0765Sfo", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise48", + "id": "tuck_ice_cream_maker", + "level": "Level 6", + "title": "Tuck Ice Cream Maker", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "AszLwoAvLKg", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise49", + "id": "tuck_front_lever_row", + "level": "Level 7", + "title": "Tuck Front Lever Row", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "F-xEL0Ot0HA", + "defaultSet": "weighted" + }, + { + "exerciseId": "exercise50", + "id": "advanced_tuck_front_lever_row", + "level": "Level 8", + "title": "Advanced Tuck Front Lever Row", + "description": "3x(5-8)", + "type": "exercise", + "youTubeId": "cVdb8oUGKAw", + "defaultSet": "weighted" + } + ] +} \ No newline at end of file diff --git a/DashboardCategoryViewCell.xib b/BodyweightFitness/UI/Cell/DashboardCategoryCell.xib similarity index 86% rename from DashboardCategoryViewCell.xib rename to BodyweightFitness/UI/Cell/DashboardCategoryCell.xib index ea4d1d1..8884f4a 100644 --- a/DashboardCategoryViewCell.xib +++ b/BodyweightFitness/UI/Cell/DashboardCategoryCell.xib @@ -1,12 +1,12 @@ - + - + - + diff --git a/DashboardDoubleItemViewCell.xib b/BodyweightFitness/UI/Cell/DashboardDoubleItemCell.xib similarity index 95% rename from DashboardDoubleItemViewCell.xib rename to BodyweightFitness/UI/Cell/DashboardDoubleItemCell.xib index 5215301..6351d49 100644 --- a/DashboardDoubleItemViewCell.xib +++ b/BodyweightFitness/UI/Cell/DashboardDoubleItemCell.xib @@ -1,12 +1,12 @@ - + - + - + diff --git a/DashboardSectionViewCell.xib b/BodyweightFitness/UI/Cell/DashboardSectionCell.xib similarity index 91% rename from DashboardSectionViewCell.xib rename to BodyweightFitness/UI/Cell/DashboardSectionCell.xib index d7541b3..7bbbff1 100644 --- a/DashboardSectionViewCell.xib +++ b/BodyweightFitness/UI/Cell/DashboardSectionCell.xib @@ -1,12 +1,12 @@ - + - + - + diff --git a/DashboardSingleItemViewCell.xib b/BodyweightFitness/UI/Cell/DashboardSingleItemCell.xib similarity index 91% rename from DashboardSingleItemViewCell.xib rename to BodyweightFitness/UI/Cell/DashboardSingleItemCell.xib index d47798a..46399c1 100644 --- a/DashboardSingleItemViewCell.xib +++ b/BodyweightFitness/UI/Cell/DashboardSingleItemCell.xib @@ -1,13 +1,13 @@ - + - + - + diff --git a/CardViewCell.xib b/BodyweightFitness/UI/Cell/ProgressCardCell.xib similarity index 86% rename from CardViewCell.xib rename to BodyweightFitness/UI/Cell/ProgressCardCell.xib index 678d72f..75d5689 100644 --- a/CardViewCell.xib +++ b/BodyweightFitness/UI/Cell/ProgressCardCell.xib @@ -1,13 +1,13 @@ - + - + - + @@ -17,8 +17,8 @@ - @@ -61,7 +62,7 @@ - + diff --git a/SectionViewCell.xib b/BodyweightFitness/UI/Cell/ProgressSectionCell.xib similarity index 87% rename from SectionViewCell.xib rename to BodyweightFitness/UI/Cell/ProgressSectionCell.xib index 1d45fd7..ed28b6c 100644 --- a/SectionViewCell.xib +++ b/BodyweightFitness/UI/Cell/ProgressSectionCell.xib @@ -1,13 +1,13 @@ - + - + - + diff --git a/BodyweightFitness/UI/Cell/SettingsActionCell.xib b/BodyweightFitness/UI/Cell/SettingsActionCell.xib new file mode 100644 index 0000000..aca04de --- /dev/null +++ b/BodyweightFitness/UI/Cell/SettingsActionCell.xib @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/BodyweightFitness/UI/Cell/SettingsActionSubtitleCell.xib b/BodyweightFitness/UI/Cell/SettingsActionSubtitleCell.xib new file mode 100644 index 0000000..a1e12ba --- /dev/null +++ b/BodyweightFitness/UI/Cell/SettingsActionSubtitleCell.xib @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BodyweightFitness/UI/Cell/SettingsTextCell.xib b/BodyweightFitness/UI/Cell/SettingsTextCell.xib new file mode 100644 index 0000000..c1446c5 --- /dev/null +++ b/BodyweightFitness/UI/Cell/SettingsTextCell.xib @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BodyweightFitness/UI/Cell/SettingsToggleCell.xib b/BodyweightFitness/UI/Cell/SettingsToggleCell.xib new file mode 100644 index 0000000..7967dcc --- /dev/null +++ b/BodyweightFitness/UI/Cell/SettingsToggleCell.xib @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BodyweightFitness/UI/Cell/SideViewHeaderCell.xib b/BodyweightFitness/UI/Cell/SideViewHeaderCell.xib new file mode 100644 index 0000000..a037e97 --- /dev/null +++ b/BodyweightFitness/UI/Cell/SideViewHeaderCell.xib @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BodyweightFitness/UI/Cell/SideViewMenuCell.xib b/BodyweightFitness/UI/Cell/SideViewMenuCell.xib new file mode 100644 index 0000000..45157ce --- /dev/null +++ b/BodyweightFitness/UI/Cell/SideViewMenuCell.xib @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/CalendarCardViewCell.xib b/BodyweightFitness/UI/Cell/WorkoutLogCardCell.xib similarity index 92% rename from CalendarCardViewCell.xib rename to BodyweightFitness/UI/Cell/WorkoutLogCardCell.xib index 878b940..37065c1 100644 --- a/CalendarCardViewCell.xib +++ b/BodyweightFitness/UI/Cell/WorkoutLogCardCell.xib @@ -7,7 +7,7 @@ - + @@ -30,22 +30,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BodyweightFitness/UI/NavigationView.xib b/BodyweightFitness/UI/NavigationView.xib new file mode 100644 index 0000000..7f0ac94 --- /dev/null +++ b/BodyweightFitness/UI/NavigationView.xib @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ProgressGeneralViewController.xib b/BodyweightFitness/UI/ProgressGeneralViewController.xib similarity index 99% rename from ProgressGeneralViewController.xib rename to BodyweightFitness/UI/ProgressGeneralViewController.xib index c4dedef..cb591fe 100644 --- a/ProgressGeneralViewController.xib +++ b/BodyweightFitness/UI/ProgressGeneralViewController.xib @@ -76,7 +76,7 @@ diff --git a/ProgressPageViewController.xib b/BodyweightFitness/UI/ProgressPageViewController.xib similarity index 100% rename from ProgressPageViewController.xib rename to BodyweightFitness/UI/ProgressPageViewController.xib diff --git a/BodyweightFitness/UI/RootView.xib b/BodyweightFitness/UI/RootView.xib new file mode 100644 index 0000000..e975f21 --- /dev/null +++ b/BodyweightFitness/UI/RootView.xib @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BodyweightFitness/UI/SettingsView.xib b/BodyweightFitness/UI/SettingsView.xib new file mode 100644 index 0000000..4563045 --- /dev/null +++ b/BodyweightFitness/UI/SettingsView.xib @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BodyweightFitness/UI/SideView.xib b/BodyweightFitness/UI/SideView.xib new file mode 100644 index 0000000..d8d2b82 --- /dev/null +++ b/BodyweightFitness/UI/SideView.xib @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SupportDeveloperView.xib b/BodyweightFitness/UI/SupportDeveloperView.xib similarity index 100% rename from SupportDeveloperView.xib rename to BodyweightFitness/UI/SupportDeveloperView.xib diff --git a/BodyweightFitness/UI/TimedView.xib b/BodyweightFitness/UI/TimedView.xib new file mode 100644 index 0000000..b798494 --- /dev/null +++ b/BodyweightFitness/UI/TimedView.xib @@ -0,0 +1,179 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BodyweightFitness/UI/WeightedView.xib b/BodyweightFitness/UI/WeightedView.xib new file mode 100644 index 0000000..c183dbb --- /dev/null +++ b/BodyweightFitness/UI/WeightedView.xib @@ -0,0 +1,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BodyweightFitness/UI/Window.xib b/BodyweightFitness/UI/Window.xib new file mode 100644 index 0000000..5cac855 --- /dev/null +++ b/BodyweightFitness/UI/Window.xib @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/BodyweightFitness/UI/WorkoutLogView.xib b/BodyweightFitness/UI/WorkoutLogView.xib new file mode 100644 index 0000000..9705850 --- /dev/null +++ b/BodyweightFitness/UI/WorkoutLogView.xib @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BodyweightFitness/Vendor/RateMyApp.swift b/BodyweightFitness/Vendor/RateMyApp.swift new file mode 100644 index 0000000..e8246a9 --- /dev/null +++ b/BodyweightFitness/Vendor/RateMyApp.swift @@ -0,0 +1,228 @@ +import UIKit + + +class RateMyApp : UIViewController,UIAlertViewDelegate{ + + private let kTrackingAppVersion = "kRateMyApp_TrackingAppVersion" + private let kFirstUseDate = "kRateMyApp_FirstUseDate" + private let kAppUseCount = "kRateMyApp_AppUseCount" + private let kSpecialEventCount = "kRateMyApp_SpecialEventCount" + private let kDidRateVersion = "kRateMyApp_DidRateVersion" + private let kDeclinedToRate = "kRateMyApp_DeclinedToRate" + private let kRemindLater = "kRateMyApp_RemindLater" + private let kRemindLaterPressedDate = "kRateMyApp_RemindLaterPressedDate" + + private var reviewURL = "itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=" + private var reviewURLiOS7 = "itms-apps://itunes.apple.com/app/id" + + + var promptAfterDays: Double = 3 + var promptAfterUses = 5 + var promptAfterCustomEventsCount = 10 + var daysBeforeReminding:Double = 1 + + var alertTitle = NSLocalizedString("Rate the app", comment: "RateMyApp") + var alertMessage = "" + var alertOKTitle = NSLocalizedString("Rate it now", comment: "RateMyApp") + var alertCancelTitle = NSLocalizedString("Don't bother me again", comment: "RateMyApp") + var alertRemindLaterTitle = NSLocalizedString("Remind me later", comment: "RateMyApp") + var appID = "" + + + class var sharedInstance : RateMyApp { + struct Static { + static let instance : RateMyApp = RateMyApp() + } + return Static.instance + } + + internal required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + private override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + + } + + private func initAllSettings(){ + let prefs = NSUserDefaults.standardUserDefaults() + + prefs.setObject(getCurrentAppVersion(), forKey: kTrackingAppVersion) + prefs.setObject(NSDate(), forKey: kFirstUseDate) + prefs.setInteger(1, forKey: kAppUseCount) + prefs.setInteger(0, forKey: kSpecialEventCount) + prefs.setBool(false, forKey: kDidRateVersion) + prefs.setBool(false, forKey: kDeclinedToRate) + prefs.setBool(false, forKey: kRemindLater) + + } + + func trackEventUsage(){ + + incrementValueForKey(name: kSpecialEventCount) + + } + + func trackAppUsage(){ + + incrementValueForKey(name: kAppUseCount) + + } + + private func isFirstTime()->Bool{ + + let prefs = NSUserDefaults.standardUserDefaults() + + let trackingAppVersion = prefs.objectForKey(kTrackingAppVersion) as? NSString + + if((trackingAppVersion == nil) || !(getCurrentAppVersion().isEqualToString(trackingAppVersion! as String))) + { + return true + } + + return false + + } + + private func incrementValueForKey(name name:String){ + + if(appID.characters.count == 0) + { + fatalError("Set iTunes connect appID to proceed, you may enter some random string for testing purpose. See line number 59") + } + + if(isFirstTime()) + { + initAllSettings() + + } + else + { + let prefs = NSUserDefaults.standardUserDefaults() + let currentCount = prefs.integerForKey(name) + prefs.setInteger(currentCount+1, forKey: name) + + } + + if(shouldShowAlert()) + { + showRatingAlert() + } + + } + + private func shouldShowAlert() -> Bool{ + let prefs = NSUserDefaults.standardUserDefaults() + + let usageCount = prefs.integerForKey(kAppUseCount) + let eventsCount = prefs.integerForKey(kSpecialEventCount) + + let firstUse = prefs.objectForKey(kFirstUseDate) as! NSDate + + let timeInterval = NSDate().timeIntervalSinceDate(firstUse) + + let daysCount = ((timeInterval / 3600) / 24) + + let hasRatedCurrentVersion = prefs.boolForKey(kDidRateVersion) + + let hasDeclinedToRate = prefs.boolForKey(kDeclinedToRate) + + let hasChosenRemindLater = prefs.boolForKey(kRemindLater) + + if(hasDeclinedToRate) + { + return false + } + + if(hasRatedCurrentVersion) + { + return false + } + + if(hasChosenRemindLater) + { + let remindLaterDate = prefs.objectForKey(kFirstUseDate) as! NSDate + + let timeInterval = NSDate().timeIntervalSinceDate(remindLaterDate) + + let remindLaterDaysCount = ((timeInterval / 3600) / 24) + + return (remindLaterDaysCount >= daysBeforeReminding) + } + + if(usageCount >= promptAfterUses) + { + return true + } + + if(daysCount >= promptAfterDays) + { + return true + } + + if(eventsCount >= promptAfterCustomEventsCount) + { + return true + } + + return false + } + + + private func showRatingAlert(){ + + let infoDocs : NSDictionary = NSBundle.mainBundle().infoDictionary! + let appname : NSString = infoDocs.objectForKey("CFBundleName") as! NSString + + var message = NSLocalizedString("If you found %@ useful, please take a moment to rate it", comment: "RateMyApp") + message = String(format:message, appname) + + if(alertMessage.characters.count == 0) + { + alertMessage = message + } + + + let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: UIAlertControllerStyle.Alert) + + alert.addAction(UIAlertAction(title: alertOKTitle, style:.Destructive, handler: { alertAction in + self.okButtonPressed() + alert.dismissViewControllerAnimated(true, completion: nil) + })) + + alert.addAction(UIAlertAction(title: alertCancelTitle, style:.Cancel, handler:{ alertAction in + self.cancelButtonPressed() + alert.dismissViewControllerAnimated(true, completion: nil) + })) + + alert.addAction(UIAlertAction(title: alertRemindLaterTitle, style:.Default, handler: { alertAction in + self.remindLaterButtonPressed() + alert.dismissViewControllerAnimated(true, completion: nil) + })) + + let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate + let controller = appDelegate.window?.rootViewController + + controller?.presentViewController(alert, animated: true, completion: nil) + } + + private func okButtonPressed() { + NSUserDefaults.standardUserDefaults().setBool(true, forKey: kDidRateVersion) + let appStoreURL = NSURL(string:reviewURLiOS7+appID) + UIApplication.sharedApplication().openURL(appStoreURL!) + } + + private func cancelButtonPressed() { + NSUserDefaults.standardUserDefaults().setBool(true, forKey: kDeclinedToRate) + } + + private func remindLaterButtonPressed() { + NSUserDefaults.standardUserDefaults().setBool(true, forKey: kRemindLater) + NSUserDefaults.standardUserDefaults().setObject(NSDate(), forKey: kRemindLaterPressedDate) + } + + private func getCurrentAppVersion() -> NSString { + return (NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString") as! NSString) + } +} \ No newline at end of file diff --git a/CardView.swift b/BodyweightFitness/View/CardView.swift similarity index 100% rename from CardView.swift rename to BodyweightFitness/View/CardView.swift diff --git a/LogWorkoutButton.swift b/BodyweightFitness/View/LogWorkoutButton.swift similarity index 100% rename from LogWorkoutButton.swift rename to BodyweightFitness/View/LogWorkoutButton.swift diff --git a/BodyweightFitness/View/SideNavigationView.swift b/BodyweightFitness/View/SideNavigationView.swift new file mode 100755 index 0000000..eda419f --- /dev/null +++ b/BodyweightFitness/View/SideNavigationView.swift @@ -0,0 +1,504 @@ +/* + * Copyright (C) 2015 - 2016, Daniel Dahan and CosmicMind, Inc. . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * * Neither the name of Material nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Rewritten to remove the functionality we don't need. + */ + +import UIKit + +public extension UIViewController { + public var sideNavigationController: SideNavigationController? { + var viewController: UIViewController? = self + + while nil != viewController { + if viewController is SideNavigationController { + return viewController as? SideNavigationController + } + + viewController = viewController?.parentViewController + } + + return nil + } +} + +public class SideNavigationView: UIView { + @IBInspectable public var x: CGFloat { + get { + return layer.frame.origin.x + } + set(value) { + layer.frame.origin.x = value + } + } + + @IBInspectable public var y: CGFloat { + get { + return layer.frame.origin.y + } + set(value) { + layer.frame.origin.y = value + } + } + + @IBInspectable public var width: CGFloat { + get { + return layer.frame.size.width + } + set(value) { + layer.frame.size.width = value + } + } + + @IBInspectable public var height: CGFloat { + get { + return layer.frame.size.height + } + set(value) { + layer.frame.size.height = value + } + } + + @IBInspectable public var position: CGPoint { + get { + return layer.position + } + set(value) { + layer.position = value + } + } + + @IBInspectable public var zPosition: CGFloat { + get { + return layer.zPosition + } + set(value) { + layer.zPosition = value + } + } + + @IBInspectable public var shadowPath: CGPath? { + get { + return layer.shadowPath + } + set(value) { + layer.shadowPath = value + } + } + + @IBInspectable public var shadowPathAutoSizeEnabled: Bool = true { + didSet { + if shadowPathAutoSizeEnabled { + layoutShadowPath() + } else { + shadowPath = nil + } + } + } + + internal func layoutShadowPath() { + // if shadowPathAutoSizeEnabled { + // if .None == depth { + // shadowPath = nil + // } else if nil == shadowPath { + // shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).CGPath + // } else { + // animate(MaterialAnimation.shadowPath(UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).CGPath, duration: 0)) + // } + // } + } +} + +public class SideNavigationController : UIViewController, UIGestureRecognizerDelegate { + private var originalX: CGFloat = 0 + + internal private(set) var panGesture: UIPanGestureRecognizer? + internal private(set) var tapGesture: UITapGestureRecognizer? + + @IBInspectable public var leftThreshold: CGFloat? + private var leftViewThreshold: CGFloat = 0 + + @IBInspectable public var userInteractionEnabled: Bool { + get { + return rootViewController.view.userInteractionEnabled + } + + set(value) { + rootViewController.view.userInteractionEnabled = value + } + } + + @IBInspectable public var animationDuration: CGFloat = 0.25 + + @IBInspectable public var enabled: Bool = true + + public private(set) var leftView: SideNavigationView? + + public var opened: Bool { + guard nil != leftView else { + return false + } + + return leftView!.x != -leftViewWidth + } + + public private(set) var rootViewController: UIViewController! + public private(set) var leftViewController: UIViewController? + + @IBInspectable public private(set) var leftViewWidth: CGFloat! + + public convenience init(rootViewController: UIViewController, leftViewController: UIViewController? = nil) { + self.init() + + self.rootViewController = rootViewController + self.leftViewController = leftViewController + + prepareView() + } + + public override func viewWillLayoutSubviews() { + super.viewWillLayoutSubviews() + + layoutSubviews() + } + + + public func transitionFromRootViewController(toViewController: UIViewController, duration: NSTimeInterval = 0.5, options: UIViewAnimationOptions = [], animations: (() -> Void)? = nil, completion: ((Bool) -> Void)? = nil) { + + rootViewController.willMoveToParentViewController(nil) + + addChildViewController(toViewController) + + self.dimView?.removeFromSuperview() + self.dimView = nil + + toViewController.view.frame = rootViewController.view.frame + + transitionFromViewController(rootViewController, + toViewController: toViewController, + duration: duration, + options: options, + animations: animations, + completion: { [unowned self] (result: Bool) in + toViewController.didMoveToParentViewController(self) + + self.rootViewController.removeFromParentViewController() + self.rootViewController = toViewController + self.rootViewController.view.clipsToBounds = true + self.rootViewController.view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight] + + self.view.sendSubviewToBack(self.rootViewController.view) + + completion?(result) + }) + } + + public func setLeftViewWidth(width: CGFloat, hidden: Bool, animated: Bool, duration: NSTimeInterval = 0.5) { + if let v: SideNavigationView = leftView { + leftViewWidth = width + + if animated { + v.shadowPathAutoSizeEnabled = false + + if hidden { + UIView.animateWithDuration(duration, + animations: { [unowned self] in + v.bounds.size.width = width + v.position.x = -width / 2 + self.dimView?.alpha = 0 + }) { [unowned self] _ in + v.shadowPathAutoSizeEnabled = true + self.layoutSubviews() + self.hideView(v) + } + } else { + UIView.animateWithDuration(duration, + animations: { [unowned self] in + v.bounds.size.width = width + v.position.x = width / 2 + self.dimView?.alpha = 0.5 + }) { [unowned self] _ in + v.shadowPathAutoSizeEnabled = true + self.layoutSubviews() + self.showView(v) + } + } + } else { + v.bounds.size.width = width + if hidden { + hideView(v) + v.position.x = -v.width / 2 + self.dimView?.alpha = 0 + } else { + v.shadowPathAutoSizeEnabled = false + + showView(v) + v.position.x = width / 2 + self.dimView?.alpha = 0.5 + v.shadowPathAutoSizeEnabled = true + } + layoutSubviews() + } + + } + } + + public func toggleLeftView(velocity: CGFloat = 0) { + opened ? closeLeftView(velocity) : openLeftView(velocity) + } + + var dimView: UIView? = nil + + public func openLeftView(velocity: CGFloat = 0) { + if enabled { + if let v: SideNavigationView = leftView { + showView(v) + + if (dimView == nil) { + dimView?.removeFromSuperview() + dimView = UIView(frame: view.frame) + + dimView!.backgroundColor = UIColor.blackColor() + dimView!.alpha = 0.0 + dimView!.userInteractionEnabled = false + view.addSubview(dimView!) + + dimView!.translatesAutoresizingMaskIntoConstraints = false + + view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat( + "|[dimView]|", + options: [], + metrics: nil, + views: ["dimView": dimView!])) + + view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat( + "V:|[dimView]|", + options: [], + metrics: nil, + views: ["dimView": dimView!])) + + UIView.animateWithDuration(0.5) { () -> Void in + self.dimView!.alpha = 0.5 + } + + } + + UIView.animateWithDuration(Double(0 == velocity ? animationDuration : fmax(0.1, fmin(1, Double(v.x / velocity)))), animations: { + v.position.x = v.width / 2 + }) + } + } + } + + public func closeLeftView(velocity: CGFloat = 0) { + if enabled { + if let v: SideNavigationView = leftView { + UIView.animateWithDuration(0.5, animations: { () -> Void in + self.dimView?.alpha = 0 + }, completion: { (complete) -> Void in + self.dimView?.removeFromSuperview() + self.dimView = nil + }) + + UIView.animateWithDuration(Double(0 == velocity ? animationDuration : fmax(0.1, fmin(1, Double(v.x / velocity)))), + animations: { + v.position.x = -v.width / 2 + }) { [unowned self] _ in + self.hideView(v) + } + } + } + } + + public func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool { + if gestureRecognizer == panGesture { + return opened || isPointContainedWithinLeftViewThreshold(touch.locationInView(view)) + } + return opened && gestureRecognizer == tapGesture + } + + @objc(handlePanGesture:) + internal func handlePanGesture(recognizer: UIPanGestureRecognizer) { + if enabled && (opened || isPointContainedWithinLeftViewThreshold(recognizer.locationInView(view))) { + if let v: SideNavigationView = leftView { + recognizer.locationInView(view) + + // Animate the panel. + switch recognizer.state { + case .Began: + originalX = v.position.x + + showView(v) + case .Changed: + let w: CGFloat = v.width + let translationX: CGFloat = recognizer.translationInView(v).x + + v.position.x = originalX + translationX > (w / 2) ? (w / 2) : originalX + translationX + case .Ended, .Cancelled, .Failed: + let p: CGPoint = recognizer.velocityInView(recognizer.view) + let x: CGFloat = p.x >= 1000 || p.x <= -1000 ? p.x : 0 + + if v.x <= -leftViewWidth + leftViewThreshold || x < -1000 { + closeLeftView(x) + } else { + openLeftView(x) + } + case .Possible: + break + } + } + } + } + + @objc(handleTapGesture:) + internal func handleTapGesture(recognizer: UITapGestureRecognizer) { + if opened { + if let v: SideNavigationView = leftView { + if enabled && opened && !isPointContainedWithinView(v, point: recognizer.locationInView(v)) { + closeLeftView() + } + } + } + } + + private func prepareView() { + view.clipsToBounds = true + + prepareRootViewController() + + prepareLeftView() + prepareLeftViewController() + + prepareGestures() + } + + private func prepareRootViewController() { + rootViewController.view.clipsToBounds = true + rootViewController.view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight] + prepareViewControllerWithinContainer(rootViewController, container: view) + } + + private func prepareLeftViewController() { + if let v: SideNavigationView = leftView { + leftViewController?.view.clipsToBounds = true + leftViewController?.view.autoresizingMask = [.FlexibleWidth, .FlexibleHeight] + prepareViewControllerWithinContainer(leftViewController, container: v) + } + } + + private func prepareLeftView() { + if nil == leftViewController { + enabled = false + } else { + leftViewWidth = UIDevice.currentDevice().userInterfaceIdiom == .Phone ? 280 : 320 + leftView = SideNavigationView() + leftView!.frame = CGRectMake(0, 0, leftViewWidth, view.frame.height) + leftView!.backgroundColor = UIColor.clearColor() + view.addSubview(leftView!) + + leftView!.hidden = true + leftView!.position.x = -leftViewWidth / 2 + leftView!.zPosition = 2000 + } + } + + private func prepareViewControllerWithinContainer(viewController: UIViewController?, container: UIView) { + if let v: UIViewController = viewController { + addChildViewController(v) + container.addSubview(v.view) + container.sendSubviewToBack(v.view) + v.didMoveToParentViewController(self) + } + } + + private func prepareGestures() { + if nil == panGesture { + panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture)) + panGesture!.delegate = self + view.addGestureRecognizer(panGesture!) + } + + if nil == tapGesture { + tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture)) + tapGesture!.delegate = self + tapGesture!.cancelsTouchesInView = false + view.addGestureRecognizer(tapGesture!) + } + } + + private func removeGestures() { + if let v: UIPanGestureRecognizer = panGesture { + view.removeGestureRecognizer(v) + panGesture = nil + } + if let v: UITapGestureRecognizer = tapGesture { + view.removeGestureRecognizer(v) + tapGesture = nil + } + } + + private func isPointContainedWithinLeftViewThreshold(point: CGPoint) -> Bool { + return point.x <= leftViewThreshold + } + + private func isPointContainedWithinView(container: UIView, point: CGPoint) -> Bool { + return CGRectContainsPoint(container.bounds, point) + } + + private func showView(container: SideNavigationView) { + userInteractionEnabled = false + container.layer.shadowOffset = CGSizeMake(0.2, 0.2) + container.layer.shadowOpacity = 0.5 + container.layer.shadowRadius = 1 + container.layoutShadowPath() + container.hidden = false + } + + private func hideView(container: SideNavigationView) { + userInteractionEnabled = true + container.layer.shadowOffset = CGSizeZero + container.layer.shadowOpacity = 0 + container.layer.shadowRadius = 0 + container.layoutShadowPath() + container.hidden = true + } + + private func layoutSubviews() { + if let v: SideNavigationView = leftView { + v.width = leftViewWidth + v.height = view.bounds.height + leftViewThreshold = nil == leftThreshold ? leftViewWidth / 2 : leftThreshold! + if let vc: UIViewController = leftViewController { + vc.view.frame.size.width = v.width + vc.view.frame.size.height = v.height + vc.view.center = CGPointMake(v.width / 2, v.height / 2) + } + } + } +} \ No newline at end of file diff --git a/SnackBar.swift b/BodyweightFitness/View/SnackBar.swift similarity index 100% rename from SnackBar.swift rename to BodyweightFitness/View/SnackBar.swift diff --git a/BodyweightFitnessTests/BodyweightFitnessTests.swift b/BodyweightFitnessTests/BodyweightFitnessTests.swift new file mode 100644 index 0000000..7c95b25 --- /dev/null +++ b/BodyweightFitnessTests/BodyweightFitnessTests.swift @@ -0,0 +1,251 @@ +import Foundation +import XCTest + +@testable import Bodyweight_Fitness + +class TestRoutine { + var id = "Routine-" + NSUUID().UUIDString + var routineId = "routine0" + var title = "Bodyweight Fitness" + var subtitle = "Recommended Routine" + var startTime = NSDate() + var lastUpdatedTime = NSDate() + + var categories = [TestCategory]() + var sections = [TestSection]() + var exercises = [TestExercise]() +} + +class TestCategory { + var id = "Category-" + NSUUID().UUIDString + var categoryId = "" + var title = "" + var routine: TestRoutine? = nil + + var sections = [TestSection]() + var exercises = [TestExercise]() +} + +class TestExercise { + var id = "Exercise-" + NSUUID().UUIDString + var exerciseId = "" + var title = "" + var desc = "" + var defaultSet = "" + var visible = true + + var routine: TestRoutine? = nil + var category: TestCategory? = nil + var section: TestSection? = nil + + var sets = [TestSet]() +} + +class TestSection { + var id = "Section-" + NSUUID().UUIDString + var sectionId = "" + var title = "" + var mode = "" + var routine: TestRoutine? = nil + var category: TestCategory? = nil + + var exercises = [TestExercise]() +} + +class TestSet { + var id = "Set-" + NSUUID().UUIDString + var isTimed = false + var weight = 0.0 + var reps = 0 + var seconds = 0 + var exercise: TestExercise? = nil +} + +class BodyweightFitnessTests: XCTestCase { + var oldSchema = Routine() + var newSchema = Routine() + + override func setUp() { + super.setUp() + + oldSchema = Routine(fileName: "TestRoutine") + newSchema = Routine(fileName: "Routine") + } + + override func tearDown() { + super.tearDown() + } + + func testIsValidSchemaShouldEqualTrue() { + let testRoutine = buildRoutine(oldSchema) + + XCTAssertTrue(isValidSchema(oldSchema, currentSchema: testRoutine)) + } + + func testIsValidSchemaShouldEqualFalse() { + let testRoutine = buildRoutine(oldSchema) + + XCTAssertFalse(isValidSchema(newSchema, currentSchema: testRoutine)) + } + + func testDifferentSchemaMigrationShouldSucceed() { + let newRoutine = Routine(fileName: "Routine") + let currentRoutine = Routine(fileName: "TestRoutine") + + let currentSchema = buildRoutine(currentRoutine) + + currentSchema.exercises[0].sets[0].reps = 5 + currentSchema.exercises[0].sets[0].seconds = 25 + currentSchema.exercises[1].sets[0].reps = 2 + currentSchema.exercises[2].sets[0].reps = 3 + currentSchema.exercises[3].sets[0].reps = 2 + currentSchema.exercises[3].sets[0].seconds = 12 + currentSchema.exercises[4].sets[0].reps = 10 + + let migratedSchema = migrateDatabaseIfNeeded(newRoutine, currentSchema: currentSchema) + + let fakeSchema = buildRoutine(newRoutine) + fakeSchema.startTime = currentSchema.startTime + fakeSchema.lastUpdatedTime = currentSchema.lastUpdatedTime + + XCTAssert(migratedSchema.startTime == fakeSchema.startTime) + XCTAssert(migratedSchema.lastUpdatedTime == fakeSchema.lastUpdatedTime) + + for (_, exercise) in migratedSchema.exercises.enumerate() { + for (_, set) in exercise.sets.enumerate() { + if let oldExercise = currentSchema.exercises.filter({ + $0.exerciseId == exercise.exerciseId + }).first { + XCTAssertEqual(set.reps, oldExercise.sets[0].reps) + XCTAssertEqual(set.seconds, oldExercise.sets[0].seconds) + } + } + } + } + + func migrateDatabaseIfNeeded(routine: Routine, currentSchema: TestRoutine) -> TestRoutine { + if (!isValidSchema(routine, currentSchema: currentSchema)) { + let newSchema = buildRoutine(routine) + + newSchema.startTime = currentSchema.startTime + newSchema.lastUpdatedTime = currentSchema.lastUpdatedTime + + for exercise in newSchema.exercises { + if let currentExercise = currentSchema.exercises.filter({ + $0.exerciseId == exercise.exerciseId + }).first { + exercise.sets = currentExercise.sets + } + } + + return newSchema + } + + return currentSchema + } + + func isValidSchema(routine: Routine, currentSchema: TestRoutine) -> Bool { + for exercise in routine.exercises { + if let exercise = exercise as? Exercise { + let containsExercise = currentSchema.exercises.contains({ + $0.exerciseId == exercise.exerciseId + }) + + if (!containsExercise) { + return false + } + } + } + + return true + } + + func buildRoutine(routine: Routine) -> TestRoutine { + let testRoutine = TestRoutine() + testRoutine.routineId = "routine0" + testRoutine.startTime = NSDate() + testRoutine.lastUpdatedTime = NSDate() + + var testCategory: TestCategory? + var testSection: TestSection? + + for exercise in routine.exercises { + if let exercise = exercise as? Exercise { + + let testExercise = TestExercise() + testExercise.exerciseId = exercise.exerciseId + testExercise.title = exercise.title + testExercise.desc = exercise.desc + testExercise.defaultSet = exercise.defaultSet + + let testSet = TestSet() + testSet.exercise = testExercise + + if(testExercise.defaultSet == "weighted") { + testSet.isTimed = false + } else { + testSet.isTimed = true + } + + testExercise.sets.append(testSet) + + if((testCategory == nil) || !(testCategory?.categoryId == exercise.category?.categoryId)) { + let category = exercise.category! + + testCategory = TestCategory() + testCategory?.categoryId = category.categoryId + testCategory?.title = category.title + testCategory?.routine = testRoutine + + testRoutine.categories.append(testCategory!) + } + + if((testSection == nil) || !(testSection?.sectionId == exercise.section?.sectionId)) { + let section = exercise.section! + + testSection = TestSection() + testSection?.sectionId = section.sectionId + testSection?.title = section.title + + if (section.mode == SectionMode.All) { + testSection?.mode = "all" + } else if (section.mode == SectionMode.Pick) { + testSection?.mode = "pick" + } else { + testSection?.mode = "levels" + } + + testSection?.routine = testRoutine + testSection?.category = testCategory! + + testRoutine.sections.append(testSection!) + testCategory?.sections.append(testSection!) + } + + testExercise.routine = testRoutine + testExercise.category = testCategory! + testExercise.section = testSection! + + if(exercise.section?.mode == SectionMode.All) { + testExercise.visible = true + } else { + if let currentExercise = exercise.section?.currentExercise { + if exercise === currentExercise { + testExercise.visible = true + } else { + testExercise.visible = false + } + } else { + testExercise.visible = false + } + } + + testRoutine.exercises.append(testExercise) + testCategory?.exercises.append(testExercise) + testSection?.exercises.append(testExercise) + } + } + + return testRoutine + } +} diff --git a/BodyweightFitnessTests/Info.plist b/BodyweightFitnessTests/Info.plist old mode 100755 new mode 100644 diff --git a/BodyweightFitnessTests/RoutineTests.swift b/BodyweightFitnessTests/RoutineTests.swift deleted file mode 100644 index aac63bb..0000000 --- a/BodyweightFitnessTests/RoutineTests.swift +++ /dev/null @@ -1,160 +0,0 @@ -import XCTest - -class RoutineTests: XCTestCase { - var routine: Routine = Routine() - - func testLoadRoutineFromJSONFile() { - XCTAssertEqual(routine.loadRoutineFromFile().length, 7548) - } - - func testLinkedRoutineLoaded() { - XCTAssertEqual(routine.linkedRoutine.count, 65) - } - - func testCategoriesLoaded() { - XCTAssertEqual(routine.categories.count, 3) - } - - func testSectionsLoaded() { - XCTAssertEqual(routine.sections.count, 11) - } - - func testExercisesLoaded() { - XCTAssertEqual(routine.exercises.count, 51) - } - - func testFirstExercise() { - XCTAssertEqual(routine.getFirstExercise().title, "Wall Extensions") - } - - func testExercisesAreLinkedTogether() { - var exercise: Exercise = routine.getFirstExercise() - - XCTAssertOptionIsNil(exercise.previous) - - XCTAssertOptionIsSet(exercise.next) - XCTAssertEqual(exercise.next!.title, "Band Dislocates") - - exercise = exercise.next! - - XCTAssertOptionIsSet(exercise.previous) - XCTAssertOptionIsSet(exercise.next) - XCTAssertEqual(exercise.next!.title, "Cat/Camel Bends") - - exercise = exercise.next! - - XCTAssertOptionIsSet(exercise.previous) - XCTAssertOptionIsSet(exercise.next) - XCTAssertEqual(exercise.next!.title, "Scapular Shrugs") - - exercise = exercise.next! - - XCTAssertOptionIsSet(exercise.previous) - XCTAssertOptionIsSet(exercise.next) - XCTAssertEqual(exercise.next!.title, "Full Body Circles") - - exercise = exercise.next! - - XCTAssertOptionIsSet(exercise.previous) - XCTAssertOptionIsSet(exercise.next) - XCTAssertEqual(exercise.next!.title, "Front and Side Leg Swings") - - exercise = exercise.next! - - XCTAssertOptionIsSet(exercise.previous) - XCTAssertOptionIsSet(exercise.next) - XCTAssertEqual(exercise.next!.title, "Wrist Mobility Exercises") - - exercise = exercise.next! - - XCTAssertOptionIsSet(exercise.previous) - XCTAssertOptionIsSet(exercise.next) - XCTAssertEqual(exercise.next!.title, "Plank") - - exercise = exercise.next! - - XCTAssertOptionIsSet(exercise.previous) - XCTAssertOptionIsSet(exercise.next) - XCTAssertEqual(exercise.next!.title, "Side Plank (Do both sides)") - - exercise = exercise.next! - - XCTAssertOptionIsSet(exercise.previous) - XCTAssertOptionIsSet(exercise.next) - XCTAssertEqual(exercise.next!.title, "Reverse Plank") - - exercise = exercise.next! - - XCTAssertOptionIsSet(exercise.previous) - XCTAssertOptionIsSet(exercise.next) - XCTAssertEqual(exercise.next!.title, "Hollow Hold") - - exercise = exercise.next! - - XCTAssertOptionIsSet(exercise.previous) - XCTAssertOptionIsSet(exercise.next) - XCTAssertEqual(exercise.next!.title, "Arch") - - exercise = exercise.next! - - XCTAssertOptionIsSet(exercise.previous) - XCTAssertOptionIsSet(exercise.next) - XCTAssertEqual(exercise.next!.title, "Squat Jumps") - - exercise = exercise.next! - - XCTAssertOptionIsSet(exercise.previous) - XCTAssertOptionIsSet(exercise.next) - XCTAssertEqual(exercise.next!.title, "Wall Plank") - - exercise = exercise.next! - - XCTAssertOptionIsSet(exercise.previous) - XCTAssertOptionIsSet(exercise.next) - XCTAssertEqual(exercise.next!.title, "Parallel Bar support") - - exercise = exercise.next! - - XCTAssertOptionIsSet(exercise.previous) - XCTAssertOptionIsSet(exercise.next) - XCTAssertEqual(exercise.next!.title, "Negative Pullups") - } - - func testExercisesAreLoadedWithAllValues() { - let exercise: Exercise = routine.getFirstExercise() - - XCTAssertEqual(exercise.id, "wall_extensions") - XCTAssertEqual(exercise.title, "Wall Extensions") - XCTAssertEqual(exercise.desc, "5-10 reps") - XCTAssertEqual(exercise.type, RoutineType.Exercise) - - XCTAssertOptionIsSet(exercise.category) - XCTAssertOptionIsSet(exercise.section) - - XCTAssertEqual(exercise.category!.title, "Warmup") - XCTAssertEqual(exercise.section!.title, "Dynamic Stretches") - } - - func testModeFromString() { - XCTAssertEqual(routine.getMode("pick"), SectionMode.Pick) - XCTAssertEqual(routine.getMode("levels"), SectionMode.Levels) - XCTAssertEqual(routine.getMode("all"), SectionMode.All) - XCTAssertEqual(routine.getMode("*&@£$&*"), SectionMode.All) - } - - func XCTAssertOptionIsNil(op: AnyObject?) { - if let _ = op { - XCTFail() - } else { - XCTAssertTrue(true) - } - } - - func XCTAssertOptionIsSet(op: AnyObject?) { - if let _ = op { - XCTAssertTrue(true) - } else { - XCTFail() - } - } -} diff --git a/CardViewCell.swift b/CardViewCell.swift deleted file mode 100644 index 7361b2b..0000000 --- a/CardViewCell.swift +++ /dev/null @@ -1,38 +0,0 @@ -import UIKit - -class CardViewCell: UITableViewCell { - var parentController: UIViewController? - - @IBOutlet weak var title: UILabel! - @IBOutlet weak var subtitle: UILabel! - - var exercise: RepositoryExercise? - - override func awakeFromNib() { - super.awakeFromNib() - } - - override func setSelected(selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - } - - @IBAction func onClickFullReport(sender: AnyObject) { - if let parentController = self.parentController { - let logWorkoutController = parentController.storyboard?.instantiateViewControllerWithIdentifier("LogWorkoutController") as! LogWorkoutController - - logWorkoutController.setRepositoryRoutine( - exercise!, - repositoryRoutine: RepositoryStream.sharedInstance.getRepositoryRoutineForToday() - ) - - logWorkoutController.parentController = parentController - - parentController.modalTransitionStyle = UIModalTransitionStyle.CoverVertical - parentController.modalPresentationStyle = .CurrentContext - - parentController.presentViewController(logWorkoutController, animated: true, completion: nil) - - parentController.dim(.In, alpha: 0.5, speed: 0.5) - } - } -} diff --git a/Cartfile b/Cartfile index b95f27e..c4d47f2 100644 --- a/Cartfile +++ b/Cartfile @@ -5,4 +5,3 @@ github "realm/realm-cocoa" ~> 0.98.5 github "ReactiveX/RxSwift" ~> 2.0 github "thoughtbot/Runes" github "SwiftyJSON/SwiftyJSON" -github "CosmicMind/Material" diff --git a/Cartfile.resolved b/Cartfile.resolved index a4097c9..9bd2514 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,8 +1,7 @@ -github "CosmicMind/Material" "1.39.5" github "uacaps/PageMenu" "1.2.9" github "kitasuke/PagingMenuController" "0.8.0" github "thoughtbot/Runes" "v3.2.0" -github "ReactiveX/RxSwift" "2.3.1" +github "ReactiveX/RxSwift" "2.4" github "i-schuetz/SwiftCharts" "0.3" github "SwiftyJSON/SwiftyJSON" "2.3.3" -github "realm/realm-cocoa" "v0.98.6" +github "realm/realm-cocoa" "v0.98.8" diff --git a/DevelopedByCell.swift b/DevelopedByCell.swift deleted file mode 100644 index 570de70..0000000 --- a/DevelopedByCell.swift +++ /dev/null @@ -1,27 +0,0 @@ -import UIKit - -class DevelopedByCell: UITableViewCell { - override func awakeFromNib() { - super.awakeFromNib() - - let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer( - target: self, - action: #selector(onClick)) - - tapGesture.numberOfTapsRequired = 1 - - self.userInteractionEnabled = true - self.addGestureRecognizer(tapGesture) - - } - - func onClick(recognizer: UITapGestureRecognizer) { - if let requestUrl = NSURL(string: "https://github.com/mazurio") { - UIApplication.sharedApplication().openURL(requestUrl) - } - } - - override func setSelected(selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - } -} diff --git a/WeightUnitCell.swift b/WeightUnitCell.swift deleted file mode 100644 index 409027a..0000000 --- a/WeightUnitCell.swift +++ /dev/null @@ -1,67 +0,0 @@ -import UIKit - -class WeightUnitCell: UITableViewCell { - @IBOutlet var label: UILabel! - - override func awakeFromNib() { - super.awakeFromNib() - - if PersistenceManager.getWeightUnit() == "lbs" { - label.text = "Pounds (lbs)" - } else { - label.text = "Kilograms (kg)" - } - - let tapGesture: UITapGestureRecognizer = UITapGestureRecognizer( - target: self, - action: #selector(tapResponse)) - - tapGesture.numberOfTapsRequired = 1 - - label.userInteractionEnabled = true - label.addGestureRecognizer(tapGesture) - - } - - func tapResponse(recognizer: UITapGestureRecognizer) { - guard let button = recognizer.view else { - return - } - - let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate - - let alertController = UIAlertController( - title: nil, - message: nil, - preferredStyle: .ActionSheet) - - alertController.modalPresentationStyle = .Popover - - if let presenter = alertController.popoverPresentationController { - presenter.sourceView = button; - presenter.sourceRect = button.bounds; - } - - alertController.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil)) - alertController.addAction( - UIAlertAction(title: "Kilograms (kg)", style: .Default) { (action) in - self.label.text = "Kilograms (kg)" - - PersistenceManager.setWeightUnit("kg") - } - ) - alertController.addAction( - UIAlertAction(title: "Pounds (lbs)", style: .Default) { (action) in - self.label.text = "Pounds (lbs)" - - PersistenceManager.setWeightUnit("lbs") - } - ) - - appDelegate.settingsViewController?.presentViewController(alertController, animated: true, completion: nil) - } - - override func setSelected(selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - } -}