This repository has been archived by the owner on Feb 12, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 30753c0
Showing
207 changed files
with
16,776 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# Xcode & macOS | ||
|
||
# OS X temporary files that should never be committed | ||
.DS_Store | ||
*.swp | ||
*.lock | ||
profile | ||
|
||
# Xcode temporary files that should never be committed | ||
*~.nib | ||
|
||
# Xcode build files | ||
DerivedData/ | ||
build/ | ||
.build/ | ||
|
||
# Xcode private settings (window sizes, bookmarks, breakpoints, custom executables, smart groups) | ||
*.pbxuser | ||
*.mode1v3 | ||
*.mode2v3 | ||
*.perspectivev3 | ||
!default.pbxuser | ||
!default.mode1v3 | ||
!default.mode2v3 | ||
!default.perspectivev3 | ||
xcuserdata | ||
xcuserdata/**/* | ||
|
||
# Cocoapods: cocoapods.org | ||
Pods/ | ||
Podfile.lock | ||
|
||
## Obj-C/Swift specific | ||
*.hmap | ||
|
||
## App packaging | ||
*.ipa | ||
*.dSYM.zip | ||
*.dSYM | ||
|
||
## Playgrounds | ||
timeline.xctimeline | ||
playground.xcworkspace | ||
|
||
# Swift Package Manager | ||
Packages/ | ||
Package.pins | ||
Package.resolved | ||
|
||
# fastlane | ||
fastlane/report.xml | ||
fastlane/Preview.html | ||
fastlane/screenshots/**/*.png | ||
fastlane/test_output |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
.DS_Store | ||
/.build | ||
/Packages | ||
/*.xcodeproj | ||
xcuserdata/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// swift-tools-version:5.3 | ||
// The swift-tools-version declares the minimum version of Swift required to build this package. | ||
|
||
import PackageDescription | ||
|
||
let package = Package( | ||
name: "AppNotifications", | ||
platforms: [ | ||
.iOS(.v14), | ||
.macOS(.v11) | ||
], | ||
products: [ | ||
// Products define the executables and libraries a package produces, and make them visible to other packages. | ||
.library( | ||
name: "AppNotifications", | ||
targets: ["AppNotifications"]), | ||
], | ||
dependencies: [ | ||
// Dependencies declare other packages that this package depends on. | ||
// .package(url: /* package url */, from: "1.0.0"), | ||
], | ||
targets: [ | ||
// Targets are the basic building blocks of a package. A target can define a module or a test suite. | ||
// Targets can depend on other targets in this package, and on products in packages this package depends on. | ||
.target( | ||
name: "AppNotifications", | ||
dependencies: []), | ||
.testTarget( | ||
name: "AppNotificationsTests", | ||
dependencies: ["AppNotifications"]), | ||
] | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
# AppNotifications | ||
|
||
App notifications overlay. | ||
|
||
## Usage | ||
Add the `.appNotificationOverlay()` modifier to the selected view (i.e. root app view). |
112 changes: 112 additions & 0 deletions
112
Modules/AppNotifications/Sources/AppNotifications/AppNotifications.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
// | ||
// AppNotifications.swift | ||
// | ||
// | ||
// Created by royal on 10/07/2020. | ||
// | ||
|
||
#if !WIDGET | ||
import Foundation | ||
import SwiftUI | ||
import Combine | ||
|
||
@available (iOS 14, macOS 10.16, watchOS 7, tvOS 14, *) | ||
public final class AppNotifications: ObservableObject { | ||
public static let shared: AppNotifications = AppNotifications() | ||
|
||
@Published public var notification: NotificationData? = nil | ||
@Published public var isPresented: Bool = false | ||
|
||
private var timer: AnyCancellable? = nil | ||
private var cancellableSet: Set<AnyCancellable> = [] | ||
|
||
private init() { | ||
$notification | ||
.sink { notification in | ||
if notification == nil { | ||
self.isPresented = false | ||
return | ||
} | ||
|
||
self.isPresented = true | ||
self.instantiateTimer() | ||
} | ||
.store(in: &cancellableSet) | ||
} | ||
|
||
public func instantiateTimer() { | ||
self.timer?.cancel() | ||
self.timer = Timer.publish(every: 5, on: .main, in: .common) | ||
.autoconnect() | ||
.sink { _ in | ||
self.notification = nil | ||
self.isPresented = false | ||
self.timer?.cancel() | ||
} | ||
} | ||
|
||
public func cancelTimer() { | ||
self.timer?.cancel() | ||
} | ||
} | ||
|
||
extension AppNotifications { | ||
public struct NotificationData: Identifiable, Equatable { | ||
public enum NotificationStyle { | ||
case normal | ||
case information | ||
case warning | ||
case error | ||
case success | ||
} | ||
|
||
public init(id: UUID = UUID(), autodismisses: Bool, dismissable: Bool, style: NotificationStyle, icon: String, title: String, subtitle: String, expandedText: String? = nil) { | ||
self.id = id | ||
self.autodismisses = autodismisses | ||
self.dismissable = dismissable | ||
self.style = style | ||
self.icon = icon | ||
self.title = title | ||
self.subtitle = subtitle | ||
self.expandedText = expandedText | ||
} | ||
|
||
public init(error: String) { | ||
self.init(autodismisses: true, dismissable: true, style: .error, icon: "exclamationmark.triangle.fill", title: "Error!", subtitle: error) | ||
} | ||
|
||
public var id: UUID = UUID() | ||
var autodismisses: Bool | ||
var dismissable: Bool | ||
var style: NotificationStyle | ||
var icon: String | ||
var title: String | ||
var subtitle: String | ||
var expandedText: String? | ||
|
||
var primaryColor: Color { | ||
switch (self.style) { | ||
case .normal: return .primary | ||
case .information: return .blue | ||
case .warning: return .orange | ||
case .error: return .red | ||
case .success: return .green | ||
} | ||
} | ||
|
||
var backgroundColor: Color { | ||
switch (self.style) { | ||
#if os(macOS) | ||
case .normal: return Color(NSColor.controlBackgroundColor) | ||
#else | ||
case .normal: return Color(UIColor.tertiarySystemBackground) | ||
#endif | ||
case .information: return Color.blue.opacity(0.1) | ||
case .warning: return Color.orange.opacity(0.1) | ||
case .error: return Color.red.opacity(0.1) | ||
case .success: return Color.green.opacity(0.1) | ||
} | ||
} | ||
} | ||
} | ||
#endif |
140 changes: 140 additions & 0 deletions
140
Modules/AppNotifications/Sources/AppNotifications/NotificationsOverlay.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
// | ||
// NotificationsOverlay.swift | ||
// | ||
// | ||
// Created by royal on 10/07/2020. | ||
// | ||
|
||
#if !WIDGET | ||
import SwiftUI | ||
import Combine | ||
import os | ||
|
||
#if os(iOS) | ||
import CoreHaptics | ||
#endif | ||
|
||
@available (iOS 14, watchOS 7, macOS 10.16, tvOS 14, *) | ||
public extension View { | ||
func notificationOverlay(_ appNotifications: AppNotifications) -> some View { | ||
return self.overlay(NotificationOverlay(appNotifications: appNotifications)) | ||
} | ||
} | ||
|
||
/// Overlays a notification on top of the views | ||
@available (iOS 14, watchOS 7, macOS 10.16, tvOS 14, *) | ||
public struct NotificationOverlay: View { | ||
@ObservedObject var appNotifications: AppNotifications | ||
|
||
@State private var isExpanded: Bool = false | ||
@State private var translation = CGSize.zero | ||
|
||
private var yOffset: CGFloat { | ||
if translation.height > 0 { | ||
return translation.height * 0.075 | ||
} | ||
|
||
return translation.height | ||
} | ||
|
||
private var notificationDragGesture: some Gesture { | ||
DragGesture() | ||
.onChanged { value in | ||
translation = value.translation | ||
} | ||
.onEnded { value in | ||
if value.translation.height < -20 { | ||
appNotifications.isPresented = false | ||
} | ||
translation = CGSize.zero | ||
} | ||
} | ||
|
||
@ViewBuilder var notificationContent: some View { | ||
if let notification = appNotifications.notification { | ||
VStack(alignment: .leading) { | ||
HStack { | ||
Image(systemName: notification.icon) | ||
.font(.system(size: 26, weight: .bold, design: .default)) | ||
.id(notification.icon) | ||
.foregroundColor(notification.primaryColor) | ||
|
||
VStack(alignment: .leading) { | ||
Text(LocalizedStringKey(notification.title)) | ||
.font(.headline) | ||
.lineLimit(2) | ||
.id(notification.title) | ||
.foregroundColor(notification.primaryColor) | ||
|
||
Text(LocalizedStringKey(notification.subtitle)) | ||
.font(.headline) | ||
.opacity(0.5) | ||
.lineLimit(3) | ||
.id(notification.subtitle) | ||
.foregroundColor(notification.primaryColor) | ||
} | ||
.padding(.horizontal, 5) | ||
|
||
Spacer() | ||
} | ||
|
||
if let expandedText = notification.expandedText, | ||
isExpanded { | ||
VStack { | ||
Text(LocalizedStringKey(expandedText)) | ||
.font(.headline) | ||
.multilineTextAlignment(.leading) | ||
.lineLimit(nil) | ||
.foregroundColor(notification.primaryColor) | ||
.opacity(0.75) | ||
} | ||
.transition(.opacity) | ||
.padding(.top, 5) | ||
.onAppear { | ||
appNotifications.cancelTimer() | ||
} | ||
.onDisappear { | ||
if notification.autodismisses { | ||
appNotifications.instantiateTimer() | ||
} | ||
} | ||
} | ||
} | ||
.padding() | ||
.padding(.vertical, 5) | ||
.background(notification.backgroundColor) | ||
.background(Color(UIColor.systemBackground)) | ||
.mask(RoundedRectangle(cornerRadius: 14, style: .circular)) | ||
.gesture(notificationDragGesture) | ||
.onTapGesture { | ||
if notification.expandedText != nil { | ||
#if os(iOS) | ||
UIImpactFeedbackGenerator(style: .light).impactOccurred() | ||
#endif | ||
isExpanded.toggle() | ||
if notification.autodismisses { | ||
if isExpanded { | ||
appNotifications.cancelTimer() | ||
} else { | ||
appNotifications.instantiateTimer() | ||
} | ||
} | ||
} | ||
} | ||
.shadow(color: Color.black.opacity(0.1), radius: 20, x: 0, y: 0) | ||
.offset(x: 0, y: appNotifications.isPresented ? yOffset : -200) | ||
.animation(.interpolatingSpring(mass: 0.5, stiffness: 45, damping: 45, initialVelocity: 15)) | ||
.transition(.asymmetric(insertion: .move(edge: .top), removal: .offset(x: 0, y: -200))) | ||
} | ||
} | ||
|
||
public var body: some View { | ||
VStack { | ||
notificationContent | ||
|
||
Spacer() | ||
} | ||
.padding() | ||
} | ||
} | ||
#endif |
15 changes: 15 additions & 0 deletions
15
Modules/AppNotifications/Tests/AppNotificationsTests/AppNotificationsTests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import XCTest | ||
@testable import AppNotifications | ||
|
||
final class AppNotificationsTests: XCTestCase { | ||
func testExample() { | ||
// This is an example of a functional test case. | ||
// Use XCTAssert and related functions to verify your tests produce the correct | ||
// results. | ||
XCTAssertEqual(AppNotifications().text, "Hello, World!") | ||
} | ||
|
||
static var allTests = [ | ||
("testExample", testExample), | ||
] | ||
} |
9 changes: 9 additions & 0 deletions
9
Modules/AppNotifications/Tests/AppNotificationsTests/XCTestManifests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import XCTest | ||
|
||
#if !canImport(ObjectiveC) | ||
public func allTests() -> [XCTestCaseEntry] { | ||
return [ | ||
testCase(AppNotificationsTests.allTests), | ||
] | ||
} | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import XCTest | ||
|
||
import AppNotificationsTests | ||
|
||
var tests = [XCTestCaseEntry]() | ||
tests += AppNotificationsTests.allTests() | ||
XCTMain(tests) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
.DS_Store | ||
/.build | ||
/Packages | ||
/*.xcodeproj | ||
xcuserdata/ |
Oops, something went wrong.