fix swift

This commit is contained in:
Hailey
2024-07-10 17:40:42 -07:00
parent 15a00b1864
commit 921b13dbdc
9 changed files with 98 additions and 105 deletions
+2
View File
@@ -26,6 +26,8 @@ jobs:
run: yarn lint
- name: Prettier check
run: yarn prettier --check .
- name: Lint native check
run: yarn lint-native
- name: Check & compile i18n
run: yarn intl:build
- name: Type check
+9 -9
View File
@@ -13,43 +13,43 @@ class NotificationService: UNNotificationServiceExtension {
contentHandler(request.content)
return
}
if reason == "chat-message" {
mutateWithChatMessage(bestAttempt)
} else {
mutateWithBadge(bestAttempt)
}
contentHandler(bestAttempt)
}
override func serviceExtensionTimeWillExpire() {
// If for some reason the alloted time expires, we don't actually want to display a notification
}
func createCopy(_ content: UNNotificationContent) -> UNMutableNotificationContent? {
return content.mutableCopy() as? UNMutableNotificationContent
}
func mutateWithBadge(_ content: UNMutableNotificationContent) {
var count = prefs?.integer(forKey: "badgeCount") ?? 0
count += 1
// Set the new badge number for the notification, then store that value for using later
content.badge = NSNumber(value: count)
prefs?.setValue(count, forKey: "badgeCount")
}
func mutateWithChatMessage(_ content: UNMutableNotificationContent) {
if self.prefs?.bool(forKey: "playSoundChat") == true {
mutateWithDmSound(content)
}
}
func mutateWithDefaultSound(_ content: UNMutableNotificationContent) {
content.sound = UNNotificationSound.default
}
func mutateWithDmSound(_ content: UNMutableNotificationContent) {
content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "dm.aiff"))
}
@@ -30,12 +30,11 @@ class ShareViewController: UIViewController {
}
}
private func handleText(item: NSItemProvider) async -> Void {
private func handleText(item: NSItemProvider) async {
do {
if let data = try await item.loadItem(forTypeIdentifier: "public.text") as? String {
if let encoded = data.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed),
let url = URL(string: "\(self.appScheme)://intent/compose?text=\(encoded)")
{
let url = URL(string: "\(self.appScheme)://intent/compose?text=\(encoded)") {
_ = self.openURL(url)
}
}
@@ -45,12 +44,11 @@ class ShareViewController: UIViewController {
}
}
private func handleUrl(item: NSItemProvider) async -> Void {
private func handleUrl(item: NSItemProvider) async {
do {
if let data = try await item.loadItem(forTypeIdentifier: "public.url") as? URL {
if let encoded = data.absoluteString.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed),
let url = URL(string: "\(self.appScheme)://intent/compose?text=\(encoded)")
{
let url = URL(string: "\(self.appScheme)://intent/compose?text=\(encoded)") {
_ = self.openURL(url)
}
}
@@ -60,7 +58,7 @@ class ShareViewController: UIViewController {
}
}
private func handleImages(items: [NSItemProvider]) async -> Void {
private func handleImages(items: [NSItemProvider]) async {
let firstFourItems: [NSItemProvider]
if items.count < 4 {
firstFourItems = items
@@ -72,7 +70,7 @@ class ShareViewController: UIViewController {
var imageUris = ""
for (index, item) in firstFourItems.enumerated() {
var imageUriInfo: String? = nil
var imageUriInfo: String?
do {
if let dataUri = try await item.loadItem(forTypeIdentifier: "public.image") as? URL {
@@ -100,8 +98,7 @@ class ShareViewController: UIViewController {
if valid,
let encoded = imageUris.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed),
let url = URL(string: "\(self.appScheme)://intent/compose?imageUris=\(encoded)")
{
let url = URL(string: "\(self.appScheme)://intent/compose?imageUris=\(encoded)") {
_ = self.openURL(url)
}
@@ -119,14 +116,12 @@ class ShareViewController: UIViewController {
// extension does.
if let dir = FileManager()
.containerURL(
forSecurityApplicationGroupIdentifier: "group.app.bsky")
{
forSecurityApplicationGroupIdentifier: "group.app.bsky") {
let filePath = "\(dir.absoluteString)\(ProcessInfo.processInfo.globallyUniqueString).jpeg"
if let newUri = URL(string: filePath),
let jpegData = image.jpegData(compressionQuality: 1)
{
try jpegData.write(to: newUri)
try jpegData.write(to: newUri)
return "\(newUri.absoluteString)|\(image.size.width)|\(image.size.height)"
}
}
@@ -136,7 +131,7 @@ class ShareViewController: UIViewController {
}
}
private func completeRequest() -> Void {
private func completeRequest() {
self.extensionContext?.completeRequest(returningItems: nil)
}
@@ -2,16 +2,16 @@ import ExpoModulesCore
let APP_GROUP = "group.app.bsky"
let DEFAULTS: [String:Any] = [
"playSoundChat" : true,
let DEFAULTS: [String: Any] = [
"playSoundChat": true,
"playSoundFollow": false,
"playSoundLike": false,
"playSoundMention": false,
"playSoundQuote": false,
"playSoundReply": false,
"playSoundRepost": false,
"mutedThreads": [:] as! [String:[String]],
"badgeCount": 0,
"mutedThreads": [:] as! [String: [String]],
"badgeCount": 0
]
/*
@@ -23,10 +23,10 @@ let DEFAULTS: [String:Any] = [
*/
public class ExpoBackgroundNotificationHandlerModule: Module {
let userDefaults = UserDefaults(suiteName: APP_GROUP)
public func definition() -> ModuleDefinition {
Name("ExpoBackgroundNotificationHandler")
OnCreate {
DEFAULTS.forEach { p in
if userDefaults?.value(forKey: p.key) == nil {
@@ -34,57 +34,56 @@ public class ExpoBackgroundNotificationHandlerModule: Module {
}
}
}
AsyncFunction("getAllPrefsAsync") { () -> [String:Any]? in
AsyncFunction("getAllPrefsAsync") { () -> [String: Any]? in
var keys: [String] = []
DEFAULTS.forEach { p in
keys.append(p.key)
}
return userDefaults?.dictionaryWithValues(forKeys: keys)
}
AsyncFunction("getBoolAsync") { (forKey: String) -> Bool in
if let pref = userDefaults?.bool(forKey: forKey) {
return pref
}
return false
}
AsyncFunction("getStringAsync") { (forKey: String) -> String? in
if let pref = userDefaults?.string(forKey: forKey) {
return pref
}
return nil
}
AsyncFunction("getStringArrayAsync") { (forKey: String) -> [String]? in
if let pref = userDefaults?.stringArray(forKey: forKey) {
return pref
}
return nil
}
AsyncFunction("setBoolAsync") { (forKey: String, value: Bool) -> Void in
AsyncFunction("setBoolAsync") { (forKey: String, value: Bool) in
userDefaults?.setValue(value, forKey: forKey)
}
AsyncFunction("setStringAsync") { (forKey: String, value: String) -> Void in
AsyncFunction("setStringAsync") { (forKey: String, value: String) in
userDefaults?.setValue(value, forKey: forKey)
}
AsyncFunction("setStringArrayAsync") { (forKey: String, value: [String]) -> Void in
AsyncFunction("setStringArrayAsync") { (forKey: String, value: [String]) in
userDefaults?.setValue(value, forKey: forKey)
}
AsyncFunction("addToStringArrayAsync") { (forKey: String, string: String) in
if var curr = userDefaults?.stringArray(forKey: forKey),
!curr.contains(string)
{
!curr.contains(string) {
curr.append(string)
userDefaults?.setValue(curr, forKey: forKey)
}
}
AsyncFunction("removeFromStringArrayAsync") { (forKey: String, string: String) in
if var curr = userDefaults?.stringArray(forKey: forKey) {
curr.removeAll { s in
@@ -93,7 +92,7 @@ public class ExpoBackgroundNotificationHandlerModule: Module {
userDefaults?.setValue(curr, forKey: forKey)
}
}
AsyncFunction("addManyToStringArrayAsync") { (forKey: String, strings: [String]) in
if var curr = userDefaults?.stringArray(forKey: forKey) {
strings.forEach { s in
@@ -104,7 +103,7 @@ public class ExpoBackgroundNotificationHandlerModule: Module {
userDefaults?.setValue(curr, forKey: forKey)
}
}
AsyncFunction("removeManyFromStringArrayAsync") { (forKey: String, strings: [String]) in
if var curr = userDefaults?.stringArray(forKey: forKey) {
strings.forEach { s in
@@ -113,7 +112,7 @@ public class ExpoBackgroundNotificationHandlerModule: Module {
userDefaults?.setValue(curr, forKey: forKey)
}
}
AsyncFunction("setBadgeCountAsync") { (count: Int) in
userDefaults?.setValue(count, forKey: "badgeCount")
}
@@ -5,11 +5,11 @@ import SDWebImageWebPCoder
public class ExpoBlueskyGifViewModule: Module {
public func definition() -> ModuleDefinition {
Name("ExpoBlueskyGifView")
OnCreate {
SDImageCodersManager.shared.addCoder(SDImageGIFCoder.shared)
}
AsyncFunction("prefetchAsync") { (sources: [URL]) in
SDWebImagePrefetcher.shared.prefetchURLs(sources, context: Util.createContext(), progress: nil)
}
@@ -18,27 +18,27 @@ public class ExpoBlueskyGifViewModule: Module {
Events(
"onPlayerStateChange"
)
Prop("source") { (view: GifView, prop: String) in
view.source = prop
}
Prop("placeholderSource") { (view: GifView, prop: String) in
view.placeholderSource = prop
}
Prop("autoplay") { (view: GifView, prop: Bool) in
view.autoplay = prop
}
AsyncFunction("toggleAsync") { (view: GifView) in
view.toggle()
}
AsyncFunction("playAsync") { (view: GifView) in
view.play()
}
AsyncFunction("pauseAsync") { (view: GifView) in
view.pause()
}
@@ -16,14 +16,14 @@ public class GifView: ExpoView, AVPlayerViewControllerDelegate {
)
private var isPlaying = true
private var isLoaded = false
// Requests
private var webpOperation: SDWebImageCombinedOperation?
private var placeholderOperation: SDWebImageCombinedOperation?
// Props
var source: String? = nil
var placeholderSource: String? = nil
var source: String?
var placeholderSource: String?
var autoplay = true {
didSet {
if !autoplay {
@@ -78,8 +78,7 @@ public class GifView: ExpoView, AVPlayerViewControllerDelegate {
// See:
// https://github.com/SDWebImage/SDWebImage/blob/master/Docs/HowToUse.md#using-asynchronous-image-caching-independently
if !SDImageCache.shared.diskImageDataExists(withKey: source),
let url = URL(string: placeholderSource)
{
let url = URL(string: placeholderSource) {
self.placeholderOperation = imageManager.loadImage(
with: url,
options: [.retryFailed],
@@ -132,8 +131,7 @@ public class GifView: ExpoView, AVPlayerViewControllerDelegate {
if let placeholderSource = self.placeholderSource,
imageUrl?.absoluteString == placeholderSource,
self.imageView.image == nil,
let image = image
{
let image = image {
self.setImage(image)
return
}
@@ -142,8 +140,7 @@ public class GifView: ExpoView, AVPlayerViewControllerDelegate {
imageUrl?.absoluteString == source,
// UIImage perf suckssss if the image is animated
let data = data,
let animatedImage = SDAnimatedImage(data: data)
{
let animatedImage = SDAnimatedImage(data: data) {
self.placeholderOperation?.cancel()
self.isPlaying = self.autoplay
self.isLoaded = true
@@ -3,7 +3,7 @@ import ExpoModulesCore
public class ExpoScrollForwarderModule: Module {
public func definition() -> ModuleDefinition {
Name("ExpoScrollForwarder")
View(ExpoScrollForwarderView.self) {
Prop("scrollViewTag") { (view: ExpoScrollForwarderView, prop: Int) in
view.scrollViewTag = prop
@@ -8,17 +8,17 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
self.tryFindScrollView()
}
}
private var rctScrollView: RCTScrollView?
private var rctRefreshCtrl: RCTRefreshControl?
private var cancelGestureRecognizers: [UIGestureRecognizer]?
private var animTimer: Timer?
private var initialOffset: CGFloat = 0.0
private var didImpact: Bool = false
required init(appContext: AppContext? = nil) {
super.init(appContext: appContext)
let pg = UIPanGestureRecognizer(target: self, action: #selector(callOnPan(_:)))
pg.delegate = self
self.addGestureRecognizer(pg)
@@ -34,28 +34,27 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
self.cancelGestureRecognizers = [lpg, tg]
}
// We don't want to recognize the scroll pan gesture and the swipe back gesture together
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
if gestureRecognizer is UIPanGestureRecognizer, otherGestureRecognizer is UIPanGestureRecognizer {
return false
}
return true
}
// We only want the "scroll" gesture to happen whenever the pan is vertical, otherwise it will
// interfere with the native swipe back gesture.
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
guard let gestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer else {
return true
}
let velocity = gestureRecognizer.velocity(in: self)
return abs(velocity.y) > abs(velocity.x)
}
// This will be used to cancel the scroll animation whenever we tap inside of the header. We don't need another
// recognizer for this one.
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
@@ -64,32 +63,32 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
// This will be used to cancel the animation whenever we press inside of the scroll view. We don't want to change
// the scroll view gesture's delegate, so we add an additional recognizer to detect this.
@IBAction func callOnPress(_ sender: UITapGestureRecognizer) -> Void {
@IBAction func callOnPress(_ sender: UITapGestureRecognizer) {
self.stopTimer()
}
@IBAction func callOnPan(_ sender: UIPanGestureRecognizer) -> Void {
@IBAction func callOnPan(_ sender: UIPanGestureRecognizer) {
guard let rctsv = self.rctScrollView, let sv = rctsv.scrollView else {
return
}
let translation = sender.translation(in: self).y
if sender.state == .began {
if sv.contentOffset.y < 0 {
sv.contentOffset.y = 0
}
self.initialOffset = sv.contentOffset.y
}
if sender.state == .changed {
sv.contentOffset.y = self.dampenOffset(-translation + self.initialOffset)
if sv.contentOffset.y <= -130, !didImpact {
let generator = UIImpactFeedbackGenerator(style: .light)
generator.impactOccurred()
self.didImpact = true
}
}
@@ -97,7 +96,7 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
if sender.state == .ended {
let velocity = sender.velocity(in: self).y
self.didImpact = false
if sv.contentOffset.y <= -130 {
self.rctRefreshCtrl?.forwarderBeginRefreshing()
return
@@ -108,40 +107,40 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
if abs(velocity) < 250, sv.contentOffset.y >= 0 {
return
}
self.startDecayAnimation(translation, velocity)
}
}
func startDecayAnimation(_ translation: CGFloat, _ velocity: CGFloat) {
guard let sv = self.rctScrollView?.scrollView else {
return
}
var velocity = velocity
self.enableCancelGestureRecognizers()
if velocity > 0 {
velocity = min(velocity, 5000)
} else {
velocity = max(velocity, -5000)
}
var animTranslation = -translation
self.animTimer = Timer.scheduledTimer(withTimeInterval: 1.0 / 120, repeats: true) { timer in
self.animTimer = Timer.scheduledTimer(withTimeInterval: 1.0 / 120, repeats: true) { _ in
velocity *= 0.9875
animTranslation = (-velocity / 120) + animTranslation
let nextOffset = self.dampenOffset(animTranslation + self.initialOffset)
if nextOffset <= 0 {
if self.initialOffset <= 1 {
self.scrollToOffset(0)
} else {
sv.contentOffset.y = 0
}
self.stopTimer()
return
} else {
@@ -153,61 +152,60 @@ class ExpoScrollForwarderView: ExpoView, UIGestureRecognizerDelegate {
}
}
}
func dampenOffset(_ offset: CGFloat) -> CGFloat {
if offset < 0 {
return offset - (offset * 0.55)
}
return offset
}
func tryFindScrollView() {
guard let scrollViewTag = scrollViewTag else {
return
}
// Before we switch to a different scrollview, we always want to remove the cancel gesture recognizer.
// Otherwise we might end up with duplicates when we switch back to that scrollview.
self.removeCancelGestureRecognizers()
self.rctScrollView = self.appContext?
.findView(withTag: scrollViewTag, ofType: RCTScrollView.self)
self.rctRefreshCtrl = self.rctScrollView?.scrollView.refreshControl as? RCTRefreshControl
self.addCancelGestureRecognizers()
}
func addCancelGestureRecognizers() {
self.cancelGestureRecognizers?.forEach { r in
self.rctScrollView?.scrollView?.addGestureRecognizer(r)
}
}
func removeCancelGestureRecognizers() {
self.cancelGestureRecognizers?.forEach { r in
self.rctScrollView?.scrollView?.removeGestureRecognizer(r)
}
}
func enableCancelGestureRecognizers() {
self.cancelGestureRecognizers?.forEach { r in
r.isEnabled = true
}
}
func disableCancelGestureRecognizers() {
self.cancelGestureRecognizers?.forEach { r in
r.isEnabled = false
}
}
func scrollToOffset(_ offset: Int, animated: Bool = true) -> Void {
func scrollToOffset(_ offset: Int, animated: Bool = true) {
self.rctScrollView?.scroll(toOffset: CGPoint(x: 0, y: offset), animated: animated)
}
func stopTimer() -> Void {
func stopTimer() {
self.disableCancelGestureRecognizers()
self.animTimer?.invalidate()
self.animTimer = nil
+2
View File
@@ -29,6 +29,8 @@
"test-ci": "NODE_ENV=test jest --ci --forceExit --reporters=default --reporters=jest-junit",
"test-coverage": "NODE_ENV=test jest --coverage",
"lint": "eslint --cache --ext .js,.jsx,.ts,.tsx src",
"lint-native": "swiftlint ./modules && ktlint ./modules",
"lint-native:fix": "swiftlint --fix ./modules && ktlint --format ./modules",
"typecheck": "tsc --project ./tsconfig.check.json",
"e2e:mock-server": "./jest/dev-infra/with-test-redis-and-db.sh ts-node --project tsconfig.e2e.json __e2e__/mock-server.ts",
"e2e:metro": "EXPO_PUBLIC_ENV=e2e NODE_ENV=test RN_SRC_EXT=e2e.ts,e2e.tsx expo run:ios",