diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 302ab469..d563e745 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -12,6 +12,6 @@ lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cl polar: # Replace with a single Polar username buy_me_a_coffee: sameerasw thanks_dev: # Replace with a single thanks.dev username -custom: ['airsync.sameerasw.com'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] +custom: ['store.sameerasw.com'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] #template for @sameerasw diff --git a/AirSync.xcodeproj/project.pbxproj b/AirSync.xcodeproj/project.pbxproj index 80e6b1ea..f0dc031c 100644 --- a/AirSync.xcodeproj/project.pbxproj +++ b/AirSync.xcodeproj/project.pbxproj @@ -163,6 +163,116 @@ /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ + 11F6093B2EA2A88900AB6BDC /* Self Compiled */ = { + isa = XCBuildConfiguration; + baseConfigurationReferenceAnchor = B9673B592E35A2A1006D284A /* airsync-mac */; + baseConfigurationReferenceRelativePath = Configs/SelfCompiled.xcconfig; + 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; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = WCB4HTANA6; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = NO; + 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; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 26.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = NO; + SDKROOT = macosx; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_COMPILATION_MODE = wholemodule; + }; + name = "Self Compiled"; + }; + 11F6093C2EA2A88900AB6BDC /* Self Compiled */ = { + isa = XCBuildConfiguration; + baseConfigurationReferenceAnchor = B9673B592E35A2A1006D284A /* airsync-mac */; + baseConfigurationReferenceRelativePath = Configs/SelfCompiled.xcconfig; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = YES; + AUTOMATION_APPLE_EVENTS = NO; + CODE_SIGN_ENTITLEMENTS = ""; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 11; + DEAD_CODE_STRIPPING = YES; + DEVELOPMENT_TEAM = WCB4HTANA6; + ENABLE_APP_SANDBOX = NO; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + ENABLE_RESOURCE_ACCESS_PHOTO_LIBRARY = NO; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = "airsync-mac/Info.plist"; + INFOPLIST_KEY_CFBundleDisplayName = AirSync; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.productivity"; + INFOPLIST_KEY_LSUIElement = NO; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MACOSX_DEPLOYMENT_TARGET = 14.5; + MARKETING_VERSION = 2.1.1; + PRODUCT_BUNDLE_IDENTIFIER = "sameerasw.airsync-mac"; + PRODUCT_NAME = "$(TARGET_NAME)"; + REGISTER_APP_GROUPS = YES; + RUNTIME_EXCEPTION_ALLOW_DYLD_ENVIRONMENT_VARIABLES = NO; + RUNTIME_EXCEPTION_ALLOW_JIT = NO; + RUNTIME_EXCEPTION_ALLOW_UNSIGNED_EXECUTABLE_MEMORY = NO; + RUNTIME_EXCEPTION_DEBUGGING_TOOL = NO; + RUNTIME_EXCEPTION_DISABLE_EXECUTABLE_PAGE_PROTECTION = NO; + RUNTIME_EXCEPTION_DISABLE_LIBRARY_VALIDATION = YES; + STRING_CATALOG_GENERATE_SYMBOLS = YES; + SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; + SWIFT_VERSION = 5.0; + }; + name = "Self Compiled"; + }; B9673B602E35A2A3006D284A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -387,6 +497,7 @@ buildConfigurations = ( B9673B602E35A2A3006D284A /* Debug */, B9673B612E35A2A3006D284A /* Release */, + 11F6093B2EA2A88900AB6BDC /* Self Compiled */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -396,6 +507,7 @@ buildConfigurations = ( B9673B632E35A2A3006D284A /* Debug */, B9673B642E35A2A3006D284A /* Release */, + 11F6093C2EA2A88900AB6BDC /* Self Compiled */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/AirSync.xcodeproj/xcshareddata/xcschemes/AirSync Self Compiled.xcscheme b/AirSync.xcodeproj/xcshareddata/xcschemes/AirSync Self Compiled.xcscheme new file mode 100644 index 00000000..7c181537 --- /dev/null +++ b/AirSync.xcodeproj/xcshareddata/xcschemes/AirSync Self Compiled.xcscheme @@ -0,0 +1,86 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/AirSync.xcodeproj/xcshareddata/xcschemes/AirSync.xcscheme b/AirSync.xcodeproj/xcshareddata/xcschemes/AirSync.xcscheme index e545fbe5..c5dd4613 100644 --- a/AirSync.xcodeproj/xcshareddata/xcschemes/AirSync.xcscheme +++ b/AirSync.xcodeproj/xcshareddata/xcschemes/AirSync.xcscheme @@ -1,7 +1,7 @@ + version = "2.2"> + + + + Archive`. Once this process is finished, the organizer window will pop up. Select `Distribute`, then `Custom`. Select `Copy App`, then select the folder for output. `AirSync.app` will be located in that folder. + ## Contributors <3 @@ -43,3 +46,4 @@ - [httpswift/swifter](https://github.com/httpswift/swifter) - [sparkle-project/Sparkle](https://github.com/sparkle-project/Sparkle) - [ungive/media-control](https://github.com/ungive/media-control) +- [tfmart/LottieUI](https://github.com/tfmart/LottieUI) diff --git a/airsync-mac/Configs/SelfCompiled.xcconfig b/airsync-mac/Configs/SelfCompiled.xcconfig new file mode 100644 index 00000000..5d0203c7 --- /dev/null +++ b/airsync-mac/Configs/SelfCompiled.xcconfig @@ -0,0 +1 @@ +SWIFT_ACTIVE_COMPILATION_CONDITIONS=SELF_COMPILED diff --git a/airsync-mac/Core/AppState.swift b/airsync-mac/Core/AppState.swift index abf623ac..308c82bc 100644 --- a/airsync-mac/Core/AppState.swift +++ b/airsync-mac/Core/AppState.swift @@ -68,9 +68,15 @@ class AppState: ObservableObject { startClipboardMonitoring() } + #if SELF_COMPILED + self.isPlus = true + UserDefaults.standard.set(true, forKey: "isPlus") + UserDefaults.standard.lastLicenseSuccessfulCheckDate = Date().addingTimeInterval(-(24 * 60 * 60)) + #else Task { await Gumroad().checkLicenseIfNeeded() } + #endif self.scrcpyBitrate = UserDefaults.standard.integer(forKey: "scrcpyBitrate") if self.scrcpyBitrate == 0 { self.scrcpyBitrate = 4 } diff --git a/airsync-mac/Localization/de.json b/airsync-mac/Localization/de.json index 0c5d6725..66dffd60 100644 --- a/airsync-mac/Localization/de.json +++ b/airsync-mac/Localization/de.json @@ -1,28 +1,28 @@ { "app.name": "AirSync", - "menu.mirror": "Mirror", - "menu.about": "About AirSync", - "menu.checkUpdates": "Check for Updates…", + "menu.mirror": "Spiegeln", + "menu.about": "Über AirSync", + "menu.checkUpdates": "Auf Updates prüfen...", "menu.quit": "Beenden", "home.title": "AirSync", - "home.sidebar.ready": "Ready", - "onboarding.title": "Welcome to AirSync", - "notifications.empty.title": "You're all caught up!", + "home.sidebar.ready": "Fertig", + "onboarding.title": "Willkommen bei AirSync", + "notifications.empty.title": "Du bist auf dem Laufenden!", "notifications.empty.emoji": "└(=^‥^=)┐", - "notifications.actions.hide": "Hide", - "notifications.actions.dismiss": "Dismiss", + "notifications.actions.hide": "Ausblenden", + "notifications.actions.dismiss": "Verwerfen", "notifications.tab": "Benachrichtigungen", "apps.tab": "Apps", - "transfers.tab": "Transfers", + "transfers.tab": "Übertragungen", "settings.tab": "Einstellungen", - "qr.tab": "Scan QR", - "transfers.empty": "Nothing transferred yet", + "qr.tab": "QR-Code scannen", + "transfers.empty": "Noch nichts übertragen", "plus.title": "AirSync+", - "plus.why": "Why Plus?", - "plus.why.body": "Keeps me inspired to continue and maybe even to publish to the Apple app store and Google Play Store. Think of it as a little donation to keep this project alive and evolving.\nThat said, I know not everyone who wants the full experience can afford it. If that’s you, please don’t hesitate to reach out. 😊\n\nThe source code is available on GitHub, and you're more than welcome to build with all Plus features free — for personal use which also opens for contributions which is a win-win!.\nAs a thank-you for supporting the app, AirSync+ unlocks some nice extras: media controls, synced widgets, low battery alerts, wireless ADB, and more to come as I keep adding new features.\n\nEnjoy the app!\n(っ◕‿◕)っ", - "license.enterKey": "Enter license key", + "plus.why": "Wieso Plus?", + "plus.why.body": "Es motiviert mich, weiterzumachen und vielleicht sogar im Apple App Store und Google Play Store zu veröffentlichen. Betrachte es als eine kleine Spende, um dieses Projekt am Leben zu erhalten und weiterzuentwickeln.\nAllerdings weiß ich, dass sich das nicht jeder, der das volle Erlebnis genießen möchte, leisten kann. Wenn das auf dich zutrifft, zöger bitte nicht, mich zu kontaktieren. 😊\n\nDer Quellcode ist auf GitHub verfügbar und du kannst gerne das Projekt selber bauen um alle Plus-Funktionen für den persönlichen Gebrauch kostenlos zu nutzen. Außerdem ermöglicht es das Mitwirken am Projekt. Eine Win-Win-Situation!\nAls Dankeschön für deine Unterstützung der App schaltet AirSync+ einige nette Extras frei: Mediensteuerung, synchronisierte Widgets, Warnungen bei niedrigem Akkustand, drahtloses ADB und weitere Funktionen, die ich nach und nach hinzufügen werde.\n\nViel Spaß mit der App!\n(っ◕‿◕)っ\n\nÜbersetzt mit DeepL.com (kostenlose Version)", + "license.enterKey": "Lizenz-Key eingeben", "status.battery": "Batterie", "status.volume": "Lautstärke", - "media.play": "Spiel", + "media.play": "Abspielen", "media.pause": "Pause" } diff --git a/airsync-mac/Model/LicensePlanType.swift b/airsync-mac/Model/LicensePlanType.swift index 038b8218..6e3c2657 100644 --- a/airsync-mac/Model/LicensePlanType.swift +++ b/airsync-mac/Model/LicensePlanType.swift @@ -13,6 +13,9 @@ import Foundation enum LicensePlanType: String, CaseIterable, Codable, Identifiable { case membership case oneTime + #if SELF_COMPILED + case selfCompiled + #endif var id: String { rawValue } @@ -20,6 +23,9 @@ enum LicensePlanType: String, CaseIterable, Codable, Identifiable { switch self { case .membership: return "Membership" case .oneTime: return "One-Time" + #if SELF_COMPILED + case .selfCompiled: return "Self-Compiled" + #endif } } } diff --git a/airsync-mac/Screens/Settings/Components/PlusUnlockedSheet.swift b/airsync-mac/Screens/Settings/Components/PlusUnlockedSheet.swift index 950c1672..fe55aaef 100644 --- a/airsync-mac/Screens/Settings/Components/PlusUnlockedSheet.swift +++ b/airsync-mac/Screens/Settings/Components/PlusUnlockedSheet.swift @@ -45,6 +45,7 @@ struct PlusUnlockedSheet: View { } HStack(spacing: 8) { + #if !SELF_COMPILED GlassButtonView( label: "Unregister", systemImage: "xmark.circle", @@ -55,6 +56,7 @@ struct PlusUnlockedSheet: View { } ) .focusable(false) + #endif GlassButtonView( label: "Awesome", diff --git a/airsync-mac/Screens/Settings/SettingsPlusView.swift b/airsync-mac/Screens/Settings/SettingsPlusView.swift index e03581d3..1fa77c0a 100644 --- a/airsync-mac/Screens/Settings/SettingsPlusView.swift +++ b/airsync-mac/Screens/Settings/SettingsPlusView.swift @@ -70,6 +70,11 @@ struct SettingsPlusView: View { label: "Activate", systemImage: "checkmark.seal", action: { + #if SELF_COMPILED + licenseValid = true + showPlusUnlockedSheet = true + #else + Task { isCheckingLicense = true licenseValid = nil @@ -86,6 +91,7 @@ struct SettingsPlusView: View { showPlusUnlockedSheet = true } } + #endif } ) .disabled(licenseKey.isEmpty || isCheckingLicense) @@ -113,6 +119,20 @@ struct SettingsPlusView: View { } // License info display + #if SELF_COMPILED + VStack(alignment: .leading, spacing: 8) { + HStack { + Text("License Info") + .font(.headline) + Spacer() + Text(appState.isPlus ? "Self Compiled" : "License inactive") + .font(.subheadline) + .foregroundColor(appState.isPlus ? .green : .red) + } + + Divider() + } + #else if let details = appState.licenseDetails { VStack(alignment: .leading, spacing: 8) { HStack { @@ -183,6 +203,7 @@ struct SettingsPlusView: View { .foregroundColor(.red) } } + #endif } .sheet(isPresented: $showPlusUnlockedSheet) { PlusUnlockedSheet()