From 52073e90931edc5c764a0e6e521d73d10822c81a Mon Sep 17 00:00:00 2001 From: bilal Date: Wed, 10 Dec 2025 21:39:23 +0300 Subject: [PATCH] Initial Commit --- 360Clock.xcodeproj/project.pbxproj | 329 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/WorkspaceSettings.xcsettings | 5 + .../WorkspaceSettings.xcsettings | 16 + .../WorkspaceSettings.xcsettings | 16 + .../xcschemes/xcschememanagement.plist | 14 + .../xcschemes/xcschememanagement.plist | 14 + .../AppIcon.appiconset/Contents.json | 99 ++++++ 360Clock/Assets.xcassets/Contents.json | 7 + 360Clock/ClockApp.swift | 10 + 360Clock/ClockView.swift | 132 +++++++ 360Clock/IconGenerator.swift | 50 +++ РЕКОМЕНДАЦИИ_APP_STORE.md | 209 +++++++++++ 13 files changed, 908 insertions(+) create mode 100755 360Clock.xcodeproj/project.pbxproj create mode 100755 360Clock.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100755 360Clock.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings create mode 100644 360Clock.xcodeproj/project.xcworkspace/xcuserdata/bilal.xcuserdatad/WorkspaceSettings.xcsettings create mode 100755 360Clock.xcodeproj/project.xcworkspace/xcuserdata/hamidcokaev.xcuserdatad/WorkspaceSettings.xcsettings create mode 100755 360Clock.xcodeproj/xcuserdata/bilal.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100755 360Clock.xcodeproj/xcuserdata/hamidcokaev.xcuserdatad/xcschemes/xcschememanagement.plist create mode 100644 360Clock/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 360Clock/Assets.xcassets/Contents.json create mode 100755 360Clock/ClockApp.swift create mode 100755 360Clock/ClockView.swift create mode 100755 360Clock/IconGenerator.swift create mode 100644 РЕКОМЕНДАЦИИ_APP_STORE.md diff --git a/360Clock.xcodeproj/project.pbxproj b/360Clock.xcodeproj/project.pbxproj new file mode 100755 index 0000000..2af4a71 --- /dev/null +++ b/360Clock.xcodeproj/project.pbxproj @@ -0,0 +1,329 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 77; + objects = { + +/* Begin PBXFileReference section */ + 00A63A602D9073F2002E3CA7 /* 360Clock.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = 360Clock.app; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFileSystemSynchronizedRootGroup section */ + 00A63A622D9073F2002E3CA7 /* 360Clock */ = { + isa = PBXFileSystemSynchronizedRootGroup; + path = 360Clock; + sourceTree = ""; + }; +/* End PBXFileSystemSynchronizedRootGroup section */ + +/* Begin PBXFrameworksBuildPhase section */ + 00A63A5D2D9073F2002E3CA7 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 00A63A572D9073F2002E3CA7 = { + isa = PBXGroup; + children = ( + 00A63A622D9073F2002E3CA7 /* 360Clock */, + 00A63A612D9073F2002E3CA7 /* Products */, + ); + sourceTree = ""; + }; + 00A63A612D9073F2002E3CA7 /* Products */ = { + isa = PBXGroup; + children = ( + 00A63A602D9073F2002E3CA7 /* 360Clock.app */, + ); + name = Products; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 00A63A5F2D9073F2002E3CA7 /* 360Clock */ = { + isa = PBXNativeTarget; + buildConfigurationList = 00A63A6E2D9073F4002E3CA7 /* Build configuration list for PBXNativeTarget "360Clock" */; + buildPhases = ( + 00A63A5C2D9073F2002E3CA7 /* Sources */, + 00A63A5D2D9073F2002E3CA7 /* Frameworks */, + 00A63A5E2D9073F2002E3CA7 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + fileSystemSynchronizedGroups = ( + 00A63A622D9073F2002E3CA7 /* 360Clock */, + ); + name = 360Clock; + packageProductDependencies = ( + ); + productName = 360Clock; + productReference = 00A63A602D9073F2002E3CA7 /* 360Clock.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 00A63A582D9073F2002E3CA7 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1620; + LastUpgradeCheck = 1620; + TargetAttributes = { + 00A63A5F2D9073F2002E3CA7 = { + CreatedOnToolsVersion = 16.2; + }; + }; + }; + buildConfigurationList = 00A63A5B2D9073F2002E3CA7 /* Build configuration list for PBXProject "360Clock" */; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 00A63A572D9073F2002E3CA7; + minimizedProjectReferenceProxies = 1; + preferredProjectObjectVersion = 77; + productRefGroup = 00A63A612D9073F2002E3CA7 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 00A63A5F2D9073F2002E3CA7 /* 360Clock */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 00A63A5E2D9073F2002E3CA7 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 00A63A5C2D9073F2002E3CA7 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 00A63A6C2D9073F4002E3CA7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 00A63A6D2D9073F4002E3CA7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 18.2; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 00A63A6F2D9073F4002E3CA7 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"360Clock/Preview Content\""; + DEVELOPMENT_TEAM = LFMN6WUGZ7; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "bilal.-60Clock"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 00A63A702D9073F4002E3CA7 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_ASSET_PATHS = "\"360Clock/Preview Content\""; + DEVELOPMENT_TEAM = LFMN6WUGZ7; + ENABLE_PREVIEWS = YES; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchScreen_Generation = YES; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = "bilal.-60Clock"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 00A63A5B2D9073F2002E3CA7 /* Build configuration list for PBXProject "360Clock" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 00A63A6C2D9073F4002E3CA7 /* Debug */, + 00A63A6D2D9073F4002E3CA7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 00A63A6E2D9073F4002E3CA7 /* Build configuration list for PBXNativeTarget "360Clock" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 00A63A6F2D9073F4002E3CA7 /* Debug */, + 00A63A702D9073F4002E3CA7 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 00A63A582D9073F2002E3CA7 /* Project object */; +} diff --git a/360Clock.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/360Clock.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100755 index 0000000..919434a --- /dev/null +++ b/360Clock.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/360Clock.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/360Clock.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100755 index 0000000..0c67376 --- /dev/null +++ b/360Clock.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + diff --git a/360Clock.xcodeproj/project.xcworkspace/xcuserdata/bilal.xcuserdatad/WorkspaceSettings.xcsettings b/360Clock.xcodeproj/project.xcworkspace/xcuserdata/bilal.xcuserdatad/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..723a561 --- /dev/null +++ b/360Clock.xcodeproj/project.xcworkspace/xcuserdata/bilal.xcuserdatad/WorkspaceSettings.xcsettings @@ -0,0 +1,16 @@ + + + + + BuildLocationStyle + UseAppPreferences + CompilationCachingSetting + Default + CustomBuildLocationType + RelativeToDerivedData + DerivedDataLocationStyle + Default + ShowSharedSchemesAutomaticallyEnabled + + + diff --git a/360Clock.xcodeproj/project.xcworkspace/xcuserdata/hamidcokaev.xcuserdatad/WorkspaceSettings.xcsettings b/360Clock.xcodeproj/project.xcworkspace/xcuserdata/hamidcokaev.xcuserdatad/WorkspaceSettings.xcsettings new file mode 100755 index 0000000..723a561 --- /dev/null +++ b/360Clock.xcodeproj/project.xcworkspace/xcuserdata/hamidcokaev.xcuserdatad/WorkspaceSettings.xcsettings @@ -0,0 +1,16 @@ + + + + + BuildLocationStyle + UseAppPreferences + CompilationCachingSetting + Default + CustomBuildLocationType + RelativeToDerivedData + DerivedDataLocationStyle + Default + ShowSharedSchemesAutomaticallyEnabled + + + diff --git a/360Clock.xcodeproj/xcuserdata/bilal.xcuserdatad/xcschemes/xcschememanagement.plist b/360Clock.xcodeproj/xcuserdata/bilal.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..049be65 --- /dev/null +++ b/360Clock.xcodeproj/xcuserdata/bilal.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + 360Clock.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/360Clock.xcodeproj/xcuserdata/hamidcokaev.xcuserdatad/xcschemes/xcschememanagement.plist b/360Clock.xcodeproj/xcuserdata/hamidcokaev.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100755 index 0000000..049be65 --- /dev/null +++ b/360Clock.xcodeproj/xcuserdata/hamidcokaev.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,14 @@ + + + + + SchemeUserState + + 360Clock.xcscheme_^#shared#^_ + + orderHint + 0 + + + + diff --git a/360Clock/Assets.xcassets/AppIcon.appiconset/Contents.json b/360Clock/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..3542117 --- /dev/null +++ b/360Clock/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,99 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "20x20" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "29x29" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "40x40" + }, + { + "idiom" : "iphone", + "scale" : "2x", + "size" : "60x60" + }, + { + "idiom" : "iphone", + "scale" : "3x", + "size" : "60x60" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "20x20" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "29x29" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "40x40" + }, + { + "idiom" : "ipad", + "scale" : "1x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "76x76" + }, + { + "idiom" : "ipad", + "scale" : "2x", + "size" : "83.5x83.5" + }, + { + "idiom" : "ios-marketing", + "scale" : "1x", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} + diff --git a/360Clock/Assets.xcassets/Contents.json b/360Clock/Assets.xcassets/Contents.json new file mode 100644 index 0000000..6cc1226 --- /dev/null +++ b/360Clock/Assets.xcassets/Contents.json @@ -0,0 +1,7 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} + diff --git a/360Clock/ClockApp.swift b/360Clock/ClockApp.swift new file mode 100755 index 0000000..90e6941 --- /dev/null +++ b/360Clock/ClockApp.swift @@ -0,0 +1,10 @@ +import SwiftUI + +@main +struct ClockApp: App { + var body: some Scene { + WindowGroup { + ClockView() + } + } +} \ No newline at end of file diff --git a/360Clock/ClockView.swift b/360Clock/ClockView.swift new file mode 100755 index 0000000..aa441a0 --- /dev/null +++ b/360Clock/ClockView.swift @@ -0,0 +1,132 @@ +import SwiftUI + +struct ClockView: View { + @State private var currentTime = Date() + @Environment(\.colorScheme) var colorScheme + let timer = Timer.publish(every: 0.001, on: .main, in: .common).autoconnect() + + var body: some View { + VStack { + Text("360 Clock") + .font(.largeTitle) + .fontWeight(.bold) + .padding(.top) + + Text(timeString) + .font(.title2) + .foregroundColor(.secondary) + .padding(.bottom, 10) + + GeometryReader { geometry in + let size = min(geometry.size.width, geometry.size.height) + + ZStack { + // Циферблат + Circle() + .stroke(colorScheme == .dark ? Color.white : Color.black, lineWidth: 2) + .frame(width: size * 0.8, height: size * 0.8) + + // Метки на циферблате (каждые 15 градусов) + ForEach(0..<24, id: \.self) { index in + let angle = Double(index * 15) // 0, 15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240, 255, 270, 285, 300, 315, 330, 345 + let radius = size * 0.35 + // Начинаем с 0 вверху (угол -90 градусов от стандартного) + let adjustedAngle = angle - 90 + let x = cos(adjustedAngle * .pi / 180) * radius + let y = sin(adjustedAngle * .pi / 180) * radius + + // Показываем градусы + Text("\(index * 15)") + .font(.caption) + .fontWeight(.bold) + .foregroundColor(colorScheme == .dark ? Color.white : Color.black) + .offset(x: x, y: y) + } + + // Центральная точка + Circle() + .fill(Color.red) + .frame(width: 8, height: 8) + + // Секундная стрелка (60 оборотов за 1 оборот минутной стрелки) + ClockHand(angle: secondAngle, length: size * 0.35, width: 1, color: colorScheme == .dark ? Color.white : Color.black) + + // Минутная стрелка (1 оборот за градус часовой стрелки) + ClockHand(angle: minuteAngle, length: size * 0.25, width: 2, color: .blue) + + // Часовая стрелка (24-часовой формат) + ClockHand(angle: hourAngle, length: size * 0.2, width: 4, color: .red) + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + } + } + .onReceive(timer) { input in + currentTime = input + } + } + + private var timeString: String { + let formatter = DateFormatter() + formatter.timeStyle = .medium + return formatter.string(from: currentTime) + } + + // Угол часовой стрелки для 24-часового формата + private var hourAngle: Double { + let calendar = Calendar.current + let hour = calendar.component(.hour, from: currentTime) + let minute = calendar.component(.minute, from: currentTime) + let second = calendar.component(.second, from: currentTime) + + // 24-часовой формат: 15° = 1 час + // 0 часов = 0°, 1 час = 15°, 2 часа = 30°, ..., 24 часов = 360° + let baseHourAngle = Double(hour) * 15.0 + + // Добавляем плавное движение для минут и секунд + let minuteOffset = Double(minute) * 0.25 // 15° / 60 минут = 0.25° за минуту + let secondOffset = Double(second) * 0.0042 // 15° / 3600 секунд = 0.0042° за секунду + let totalAngle = baseHourAngle + minuteOffset + secondOffset + + // В SwiftUI: 0° = вверх, 90° = вправо, 180° = вниз, 270° = влево + // Нам нужно: 0 часов = вверх (0°), 6 часов = вправо (90°), 12 часов = вниз (180°), 18 часов = влево (270°) + // Простая формула: totalAngle + return totalAngle + } + + // Угол минутной стрелки (1 оборот за градус часовой стрелки) + private var minuteAngle: Double { + // Минутная стрелка делает 1 оборот (360°) за каждый градус поворота часовой стрелки + // hourAngle уже в градусах, поэтому просто умножаем на 360 + let totalAngle = hourAngle * 360.0 + // Приводим к диапазону 0-360° + return totalAngle.truncatingRemainder(dividingBy: 360.0) + } + + // Угол секундной стрелки (60 оборотов за 1 оборот минутной стрелки) + private var secondAngle: Double { + // Секундная стрелка делает 60 оборотов за 1 оборот минутной стрелки + let totalAngle = minuteAngle * 60.0 + // Приводим к диапазону 0-360° + return totalAngle.truncatingRemainder(dividingBy: 360.0) + } + +} + +struct ClockHand: View { + let angle: Double + let length: CGFloat + let width: CGFloat + let color: Color + + var body: some View { + Rectangle() + .fill(color) + .frame(width: width, height: length) + .offset(y: -length/2) // Смещаем вверх, чтобы центр был в центре циферблата + .rotationEffect(.degrees(angle)) // Поворачиваем на нужный угол + } +} + +#Preview { + ClockView() +} diff --git a/360Clock/IconGenerator.swift b/360Clock/IconGenerator.swift new file mode 100755 index 0000000..33cd212 --- /dev/null +++ b/360Clock/IconGenerator.swift @@ -0,0 +1,50 @@ +import SwiftUI + +struct IconGenerator: View { + let size: CGFloat + + var body: some View { + ZStack { + // Фон + Circle() + .fill(Color.blue) + + // Внешний круг + Circle() + .stroke(Color.white, lineWidth: size * 0.1) + .padding(size * 0.1) + + // Число 360 + Text("360") + .font(.system(size: size * 0.4, weight: .bold)) + .foregroundColor(.white) + + // Стрелки часов (упрощенные) + Rectangle() + .fill(Color.white) + .frame(width: size * 0.05, height: size * 0.3) + .offset(y: -size * 0.15) + .rotationEffect(.degrees(45)) + + Rectangle() + .fill(Color.white) + .frame(width: size * 0.03, height: size * 0.4) + .offset(y: -size * 0.2) + .rotationEffect(.degrees(135)) + + Rectangle() + .fill(Color.white) + .frame(width: size * 0.02, height: size * 0.5) + .offset(y: -size * 0.25) + .rotationEffect(.degrees(225)) + } + .frame(width: size, height: size) + } +} + +// Предварительный просмотр иконки +struct IconGenerator_Previews: PreviewProvider { + static var previews: some View { + IconGenerator(size: 200) + } +} \ No newline at end of file diff --git a/РЕКОМЕНДАЦИИ_APP_STORE.md b/РЕКОМЕНДАЦИИ_APP_STORE.md new file mode 100644 index 0000000..a34b61c --- /dev/null +++ b/РЕКОМЕНДАЦИИ_APP_STORE.md @@ -0,0 +1,209 @@ +# Рекомендации для доработки и выпуска 360 Clock в App Store + +## ✅ Исправленные проблемы + +### 1. Секундная стрелка в темной теме +- **Исправлено**: Секундная стрелка теперь корректно меняет цвет в темной теме (белый в темной теме, черный в светлой) +- **Дополнительно**: Улучшена поддержка темной темы для циферблата и меток градусов + +### 2. Иконка приложения +- **Создана структура**: Добавлена папка `Assets.xcassets/AppIcon.appiconset` +- **Требуется действие**: Необходимо добавить изображения иконок всех размеров (см. раздел ниже) + +--- + +## 🔧 Обязательные доработки перед публикацией + +### 1. Иконка приложения + +**Текущая ситуация**: Структура создана, но изображения отсутствуют. + +**Что нужно сделать**: +1. Создать иконку размером 1024x1024 пикселей (основная иконка для App Store) +2. Использовать `IconGenerator.swift` для генерации иконки или создать дизайн вручную +3. Добавить все необходимые размеры в `Assets.xcassets/AppIcon.appiconset/`: + - 20x20 (@2x, @3x) - 40x40, 60x60 + - 29x29 (@2x, @3x) - 58x58, 87x87 + - 40x40 (@2x, @3x) - 80x80, 120x120 + - 60x60 (@2x, @3x) - 120x120, 180x180 + - 76x76 (@1x, @2x) - 76x76, 152x152 (iPad) + - 83.5x83.5 (@2x) - 167x167 (iPad Pro) + - 1024x1024 (@1x) - для App Store + +**Рекомендация**: Используйте инструменты типа [App Icon Generator](https://www.appicon.co/) или создайте скрипт для экспорта из `IconGenerator`. + +### 2. Bundle Identifier + +**Проблема**: В `project.pbxproj` указан `bilal.-60Clock` (похоже на опечатку) + +**Рекомендация**: Измените на `bilal.360Clock` или более профессиональный вариант типа `com.yourname.360clock` + +**Как исправить**: +1. Откройте проект в Xcode +2. Выберите проект в навигаторе +3. Выберите таргет "360Clock" +4. Во вкладке "Signing & Capabilities" измените Bundle Identifier + +### 3. Минимальная версия iOS + +**Текущая**: iOS 18.2 (очень новая версия) + +**Рекомендация**: Понизить до iOS 17.0 или iOS 16.0 для большей совместимости + +**Как изменить**: +1. В Xcode: Project → Target → General → Minimum Deployments +2. Или в `project.pbxproj`: изменить `IPHONEOS_DEPLOYMENT_TARGET` + +### 4. Privacy Info (Обязательно с iOS 17+) + +**Требуется**: Файл `PrivacyInfo.xcprivacy` для App Store Connect + +**Что нужно**: +1. Создать файл `PrivacyInfo.xcprivacy` в корне проекта +2. Указать, какие данные собирает приложение (если не собирает - указать это) +3. Добавить файл в проект через Xcode + +**Пример содержимого** (если не собираете данные): +```xml + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + NSPrivacyCollectedDataTypes + + NSPrivacyAccessedAPITypes + + + +``` + +### 5. Описание приложения для App Store + +**Необходимо подготовить**: +- Название приложения (до 30 символов) +- Подзаголовок (до 30 символов) +- Описание (до 4000 символов) +- Ключевые слова (до 100 символов) +- Скриншоты для разных размеров устройств: + - iPhone 6.7" (iPhone 14 Pro Max, 15 Pro Max) + - iPhone 6.5" (iPhone 11 Pro Max, XS Max) + - iPhone 5.5" (iPhone 8 Plus) + - iPad Pro 12.9" + - iPad Pro 11" + +### 6. Категория и возрастной рейтинг + +**Рекомендации**: +- Категория: Утилиты (Utilities) или Образование (Education) +- Возрастной рейтинг: 4+ (приложение не содержит контента для взрослых) + +--- + +## 🎨 Рекомендации по улучшению UX/UI + +### 1. Launch Screen +- **Текущая ситуация**: Используется автоматически генерируемый экран запуска +- **Рекомендация**: Создать кастомный Launch Screen с логотипом приложения + +### 2. Адаптация для iPad +- Приложение поддерживает iPad, но можно улучшить: + - Увеличить размер циферблата на больших экранах + - Добавить поддержку Split View и Slide Over + +### 3. Анимации +- Добавить плавные переходы при смене темы +- Улучшить анимацию движения стрелок (сейчас обновление каждую миллисекунду - можно оптимизировать) + +### 4. Дополнительные функции (опционально) +- Настройки для изменения цветов стрелок +- Выбор формата времени (12/24 часа) +- Виджет для домашнего экрана +- Поддержка Apple Watch + +--- + +## 🔒 Технические требования + +### 1. Подпись кода (Code Signing) +- Убедитесь, что у вас есть: + - Apple Developer Account ($99/год) + - Сертификат разработчика + - Provisioning Profile для App Store + +### 2. Тестирование +- Протестируйте на реальных устройствах: + - iPhone (разные размеры) + - iPad (если поддерживается) + - Разные версии iOS +- Проверьте работу в темной и светлой темах +- Проверьте ориентацию экрана (портретная/ландшафтная) + +### 3. Производительность +- **Текущая проблема**: Таймер обновляется каждую миллисекунду (0.001 сек) +- **Рекомендация**: Изменить на 0.1 секунды для секундной стрелки или использовать более эффективный подход + +**Пример оптимизации**: +```swift +// Вместо 0.001 можно использовать 0.1 для секундной стрелки +let timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect() +``` + +### 4. Локализация +- **Текущая ситуация**: Только английский язык +- **Рекомендация**: Добавить поддержку русского языка (особенно если целевая аудитория - русскоязычные пользователи) + +--- + +## 📋 Чеклист перед отправкой в App Store + +### Подготовка проекта +- [ ] Исправлен Bundle Identifier +- [ ] Добавлены все размеры иконок приложения +- [ ] Создан файл PrivacyInfo.xcprivacy +- [ ] Проверена минимальная версия iOS +- [ ] Протестировано на реальных устройствах +- [ ] Проверена работа в темной/светлой теме +- [ ] Оптимизирована производительность + +### App Store Connect +- [ ] Создан App Store Connect запись +- [ ] Заполнено описание приложения +- [ ] Подготовлены скриншоты для всех размеров +- [ ] Указана категория и возрастной рейтинг +- [ ] Настроена цена и доступность по странам + +### Юридические требования +- [ ] Политика конфиденциальности (если требуется) +- [ ] Условия использования (опционально) +- [ ] Контактная информация разработчика + +### Финальная проверка +- [ ] Архив создан успешно +- [ ] Валидация прошла без ошибок +- [ ] Приложение загружено в App Store Connect +- [ ] Заполнена вся необходимая информация +- [ ] Отправлено на ревью + +--- + +## 🚀 Полезные ресурсы + +1. [App Store Review Guidelines](https://developer.apple.com/app-store/review/guidelines/) +2. [Human Interface Guidelines](https://developer.apple.com/design/human-interface-guidelines/) +3. [App Store Connect Help](https://help.apple.com/app-store-connect/) +4. [App Icon Generator](https://www.appicon.co/) + +--- + +## 📝 Примечания + +- Все исправления, связанные с кодом, уже внесены в проект +- Структура для иконок создана, но требуется добавить изображения +- Рекомендуется протестировать приложение на нескольких устройствах перед отправкой + +**Удачи с публикацией! 🎉** +