+9
-9
modules/BlueskyNSE/NotificationService.swift
+9
-9
modules/BlueskyNSE/NotificationService.swift
···
13
13
contentHandler(request.content)
14
14
return
15
15
}
16
-
16
+
17
17
if reason == "chat-message" {
18
18
mutateWithChatMessage(bestAttempt)
19
19
} else {
20
20
mutateWithBadge(bestAttempt)
21
21
}
22
-
22
+
23
23
contentHandler(bestAttempt)
24
24
}
25
-
25
+
26
26
override func serviceExtensionTimeWillExpire() {
27
27
// If for some reason the alloted time expires, we don't actually want to display a notification
28
28
}
29
-
29
+
30
30
func createCopy(_ content: UNNotificationContent) -> UNMutableNotificationContent? {
31
31
return content.mutableCopy() as? UNMutableNotificationContent
32
32
}
33
-
33
+
34
34
func mutateWithBadge(_ content: UNMutableNotificationContent) {
35
35
var count = prefs?.integer(forKey: "badgeCount") ?? 0
36
36
count += 1
37
-
37
+
38
38
// Set the new badge number for the notification, then store that value for using later
39
39
content.badge = NSNumber(value: count)
40
40
prefs?.setValue(count, forKey: "badgeCount")
41
41
}
42
-
42
+
43
43
func mutateWithChatMessage(_ content: UNMutableNotificationContent) {
44
44
if self.prefs?.bool(forKey: "playSoundChat") == true {
45
45
mutateWithDmSound(content)
46
46
}
47
47
}
48
-
48
+
49
49
func mutateWithDefaultSound(_ content: UNMutableNotificationContent) {
50
50
content.sound = UNNotificationSound.default
51
51
}
52
-
52
+
53
53
func mutateWithDmSound(_ content: UNMutableNotificationContent) {
54
54
content.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "dm.aiff"))
55
55
}
+1
-1
modules/expo-background-notification-handler/android/src/main/java/expo/modules/backgroundnotificationhandler/BackgroundNotificationHandler.kt
+1
-1
modules/expo-background-notification-handler/android/src/main/java/expo/modules/backgroundnotificationhandler/BackgroundNotificationHandler.kt
···
5
5
6
6
class BackgroundNotificationHandler(
7
7
private val context: Context,
8
-
private val notifInterface: BackgroundNotificationHandlerInterface
8
+
private val notifInterface: BackgroundNotificationHandlerInterface,
9
9
) {
10
10
fun handleMessage(remoteMessage: RemoteMessage) {
11
11
if (ExpoBackgroundNotificationHandlerModule.isForegrounded) {
+48
-47
modules/expo-background-notification-handler/android/src/main/java/expo/modules/backgroundnotificationhandler/ExpoBackgroundNotificationHandlerModule.kt
+48
-47
modules/expo-background-notification-handler/android/src/main/java/expo/modules/backgroundnotificationhandler/ExpoBackgroundNotificationHandlerModule.kt
···
8
8
var isForegrounded = false
9
9
}
10
10
11
-
override fun definition() = ModuleDefinition {
12
-
Name("ExpoBackgroundNotificationHandler")
11
+
override fun definition() =
12
+
ModuleDefinition {
13
+
Name("ExpoBackgroundNotificationHandler")
13
14
14
-
OnCreate {
15
-
NotificationPrefs(appContext.reactContext).initialize()
16
-
}
15
+
OnCreate {
16
+
NotificationPrefs(appContext.reactContext).initialize()
17
+
}
17
18
18
-
OnActivityEntersForeground {
19
-
isForegrounded = true
20
-
}
19
+
OnActivityEntersForeground {
20
+
isForegrounded = true
21
+
}
21
22
22
-
OnActivityEntersBackground {
23
-
isForegrounded = false
24
-
}
23
+
OnActivityEntersBackground {
24
+
isForegrounded = false
25
+
}
25
26
26
-
AsyncFunction("getAllPrefsAsync") {
27
-
return@AsyncFunction NotificationPrefs(appContext.reactContext).getAllPrefs()
28
-
}
27
+
AsyncFunction("getAllPrefsAsync") {
28
+
return@AsyncFunction NotificationPrefs(appContext.reactContext).getAllPrefs()
29
+
}
29
30
30
-
AsyncFunction("getBoolAsync") { forKey: String ->
31
-
return@AsyncFunction NotificationPrefs(appContext.reactContext).getBoolean(forKey)
32
-
}
31
+
AsyncFunction("getBoolAsync") { forKey: String ->
32
+
return@AsyncFunction NotificationPrefs(appContext.reactContext).getBoolean(forKey)
33
+
}
33
34
34
-
AsyncFunction("getStringAsync") { forKey: String ->
35
-
return@AsyncFunction NotificationPrefs(appContext.reactContext).getString(forKey)
36
-
}
35
+
AsyncFunction("getStringAsync") { forKey: String ->
36
+
return@AsyncFunction NotificationPrefs(appContext.reactContext).getString(forKey)
37
+
}
37
38
38
-
AsyncFunction("getStringArrayAsync") { forKey: String ->
39
-
return@AsyncFunction NotificationPrefs(appContext.reactContext).getStringArray(forKey)
40
-
}
39
+
AsyncFunction("getStringArrayAsync") { forKey: String ->
40
+
return@AsyncFunction NotificationPrefs(appContext.reactContext).getStringArray(forKey)
41
+
}
41
42
42
-
AsyncFunction("setBoolAsync") { forKey: String, value: Boolean ->
43
-
NotificationPrefs(appContext.reactContext).setBoolean(forKey, value)
44
-
}
43
+
AsyncFunction("setBoolAsync") { forKey: String, value: Boolean ->
44
+
NotificationPrefs(appContext.reactContext).setBoolean(forKey, value)
45
+
}
45
46
46
-
AsyncFunction("setStringAsync") { forKey: String, value: String ->
47
-
NotificationPrefs(appContext.reactContext).setString(forKey, value)
48
-
}
47
+
AsyncFunction("setStringAsync") { forKey: String, value: String ->
48
+
NotificationPrefs(appContext.reactContext).setString(forKey, value)
49
+
}
49
50
50
-
AsyncFunction("setStringArrayAsync") { forKey: String, value: Array<String> ->
51
-
NotificationPrefs(appContext.reactContext).setStringArray(forKey, value)
52
-
}
51
+
AsyncFunction("setStringArrayAsync") { forKey: String, value: Array<String> ->
52
+
NotificationPrefs(appContext.reactContext).setStringArray(forKey, value)
53
+
}
53
54
54
-
AsyncFunction("addToStringArrayAsync") { forKey: String, string: String ->
55
-
NotificationPrefs(appContext.reactContext).addToStringArray(forKey, string)
56
-
}
55
+
AsyncFunction("addToStringArrayAsync") { forKey: String, string: String ->
56
+
NotificationPrefs(appContext.reactContext).addToStringArray(forKey, string)
57
+
}
57
58
58
-
AsyncFunction("removeFromStringArrayAsync") { forKey: String, string: String ->
59
-
NotificationPrefs(appContext.reactContext).removeFromStringArray(forKey, string)
60
-
}
59
+
AsyncFunction("removeFromStringArrayAsync") { forKey: String, string: String ->
60
+
NotificationPrefs(appContext.reactContext).removeFromStringArray(forKey, string)
61
+
}
61
62
62
-
AsyncFunction("addManyToStringArrayAsync") { forKey: String, strings: Array<String> ->
63
-
NotificationPrefs(appContext.reactContext).addManyToStringArray(forKey, strings)
64
-
}
63
+
AsyncFunction("addManyToStringArrayAsync") { forKey: String, strings: Array<String> ->
64
+
NotificationPrefs(appContext.reactContext).addManyToStringArray(forKey, strings)
65
+
}
65
66
66
-
AsyncFunction("removeManyFromStringArrayAsync") { forKey: String, strings: Array<String> ->
67
-
NotificationPrefs(appContext.reactContext).removeManyFromStringArray(forKey, strings)
68
-
}
67
+
AsyncFunction("removeManyFromStringArrayAsync") { forKey: String, strings: Array<String> ->
68
+
NotificationPrefs(appContext.reactContext).removeManyFromStringArray(forKey, strings)
69
+
}
69
70
70
-
AsyncFunction("setBadgeCountAsync") { _: Int ->
71
-
// This does nothing on Android
71
+
AsyncFunction("setBadgeCountAsync") { _: Int ->
72
+
// This does nothing on Android
73
+
}
72
74
}
73
-
}
74
75
}
+58
-49
modules/expo-background-notification-handler/android/src/main/java/expo/modules/backgroundnotificationhandler/NotificationPrefs.kt
+58
-49
modules/expo-background-notification-handler/android/src/main/java/expo/modules/backgroundnotificationhandler/NotificationPrefs.kt
···
2
2
3
3
import android.content.Context
4
4
5
-
val DEFAULTS = mapOf<String, Any>(
6
-
"playSoundChat" to true,
7
-
"playSoundFollow" to false,
8
-
"playSoundLike" to false,
9
-
"playSoundMention" to false,
10
-
"playSoundQuote" to false,
11
-
"playSoundReply" to false,
12
-
"playSoundRepost" to false,
13
-
"mutedThreads" to mapOf<String, List<String>>()
14
-
)
5
+
val DEFAULTS =
6
+
mapOf<String, Any>(
7
+
"playSoundChat" to true,
8
+
"playSoundFollow" to false,
9
+
"playSoundLike" to false,
10
+
"playSoundMention" to false,
11
+
"playSoundQuote" to false,
12
+
"playSoundReply" to false,
13
+
"playSoundRepost" to false,
14
+
"mutedThreads" to mapOf<String, List<String>>(),
15
+
)
15
16
16
-
class NotificationPrefs (private val context: Context?) {
17
-
private val prefs = context?.getSharedPreferences("xyz.blueskyweb.app", Context.MODE_PRIVATE)
18
-
?: throw Error("Context is null")
17
+
class NotificationPrefs(
18
+
private val context: Context?,
19
+
) {
20
+
private val prefs =
21
+
context?.getSharedPreferences("xyz.blueskyweb.app", Context.MODE_PRIVATE)
22
+
?: throw Error("Context is null")
19
23
20
24
fun initialize() {
21
25
prefs
···
41
45
}
42
46
}
43
47
}
44
-
}
45
-
.apply()
48
+
}.apply()
46
49
}
47
50
48
-
fun getAllPrefs(): MutableMap<String, *> {
49
-
return prefs.all
50
-
}
51
+
fun getAllPrefs(): MutableMap<String, *> = prefs.all
51
52
52
-
fun getBoolean(key: String): Boolean {
53
-
return prefs.getBoolean(key, false)
54
-
}
53
+
fun getBoolean(key: String): Boolean = prefs.getBoolean(key, false)
55
54
56
-
fun getString(key: String): String? {
57
-
return prefs.getString(key, null)
58
-
}
55
+
fun getString(key: String): String? = prefs.getString(key, null)
59
56
60
-
fun getStringArray(key: String): Array<String>? {
61
-
return prefs.getStringSet(key, null)?.toTypedArray()
62
-
}
57
+
fun getStringArray(key: String): Array<String>? = prefs.getStringSet(key, null)?.toTypedArray()
63
58
64
-
fun setBoolean(key: String, value: Boolean) {
59
+
fun setBoolean(
60
+
key: String,
61
+
value: Boolean,
62
+
) {
65
63
prefs
66
64
.edit()
67
65
.apply {
68
66
putBoolean(key, value)
69
-
}
70
-
.apply()
67
+
}.apply()
71
68
}
72
69
73
-
fun setString(key: String, value: String) {
70
+
fun setString(
71
+
key: String,
72
+
value: String,
73
+
) {
74
74
prefs
75
75
.edit()
76
76
.apply {
77
77
putString(key, value)
78
-
}
79
-
.apply()
78
+
}.apply()
80
79
}
81
80
82
-
fun setStringArray(key: String, value: Array<String>) {
81
+
fun setStringArray(
82
+
key: String,
83
+
value: Array<String>,
84
+
) {
83
85
prefs
84
86
.edit()
85
87
.apply {
86
88
putStringSet(key, value.toSet())
87
-
}
88
-
.apply()
89
+
}.apply()
89
90
}
90
91
91
-
fun addToStringArray(key: String, string: String) {
92
+
fun addToStringArray(
93
+
key: String,
94
+
string: String,
95
+
) {
92
96
prefs
93
97
.edit()
94
98
.apply {
95
99
val set = prefs.getStringSet(key, null)?.toMutableSet() ?: mutableSetOf()
96
100
set.add(string)
97
101
putStringSet(key, set)
98
-
}
99
-
.apply()
102
+
}.apply()
100
103
}
101
104
102
-
fun removeFromStringArray(key: String, string: String) {
105
+
fun removeFromStringArray(
106
+
key: String,
107
+
string: String,
108
+
) {
103
109
prefs
104
110
.edit()
105
111
.apply {
106
112
val set = prefs.getStringSet(key, null)?.toMutableSet() ?: mutableSetOf()
107
113
set.remove(string)
108
114
putStringSet(key, set)
109
-
}
110
-
.apply()
115
+
}.apply()
111
116
}
112
117
113
-
fun addManyToStringArray(key: String, strings: Array<String>) {
118
+
fun addManyToStringArray(
119
+
key: String,
120
+
strings: Array<String>,
121
+
) {
114
122
prefs
115
123
.edit()
116
124
.apply {
117
125
val set = prefs.getStringSet(key, null)?.toMutableSet() ?: mutableSetOf()
118
126
set.addAll(strings.toSet())
119
127
putStringSet(key, set)
120
-
}
121
-
.apply()
128
+
}.apply()
122
129
}
123
130
124
-
fun removeManyFromStringArray(key: String, strings: Array<String>) {
131
+
fun removeManyFromStringArray(
132
+
key: String,
133
+
strings: Array<String>,
134
+
) {
125
135
prefs
126
136
.edit()
127
137
.apply {
128
138
val set = prefs.getStringSet(key, null)?.toMutableSet() ?: mutableSetOf()
129
139
set.removeAll(strings.toSet())
130
140
putStringSet(key, set)
131
-
}
132
-
.apply()
141
+
}.apply()
133
142
}
134
-
}
143
+
}
+23
-24
modules/expo-background-notification-handler/ios/ExpoBackgroundNotificationHandlerModule.swift
+23
-24
modules/expo-background-notification-handler/ios/ExpoBackgroundNotificationHandlerModule.swift
···
2
2
3
3
let APP_GROUP = "group.app.bsky"
4
4
5
-
let DEFAULTS: [String:Any] = [
6
-
"playSoundChat" : true,
5
+
let DEFAULTS: [String: Any] = [
6
+
"playSoundChat": true,
7
7
"playSoundFollow": false,
8
8
"playSoundLike": false,
9
9
"playSoundMention": false,
10
10
"playSoundQuote": false,
11
11
"playSoundReply": false,
12
12
"playSoundRepost": false,
13
-
"mutedThreads": [:] as! [String:[String]],
14
-
"badgeCount": 0,
13
+
"mutedThreads": [:] as! [String: [String]],
14
+
"badgeCount": 0
15
15
]
16
16
17
17
/*
···
23
23
*/
24
24
public class ExpoBackgroundNotificationHandlerModule: Module {
25
25
let userDefaults = UserDefaults(suiteName: APP_GROUP)
26
-
26
+
27
27
public func definition() -> ModuleDefinition {
28
28
Name("ExpoBackgroundNotificationHandler")
29
-
29
+
30
30
OnCreate {
31
31
DEFAULTS.forEach { p in
32
32
if userDefaults?.value(forKey: p.key) == nil {
···
34
34
}
35
35
}
36
36
}
37
-
38
-
AsyncFunction("getAllPrefsAsync") { () -> [String:Any]? in
37
+
38
+
AsyncFunction("getAllPrefsAsync") { () -> [String: Any]? in
39
39
var keys: [String] = []
40
40
DEFAULTS.forEach { p in
41
41
keys.append(p.key)
42
42
}
43
43
return userDefaults?.dictionaryWithValues(forKeys: keys)
44
44
}
45
-
45
+
46
46
AsyncFunction("getBoolAsync") { (forKey: String) -> Bool in
47
47
if let pref = userDefaults?.bool(forKey: forKey) {
48
48
return pref
49
49
}
50
50
return false
51
51
}
52
-
52
+
53
53
AsyncFunction("getStringAsync") { (forKey: String) -> String? in
54
54
if let pref = userDefaults?.string(forKey: forKey) {
55
55
return pref
56
56
}
57
57
return nil
58
58
}
59
-
59
+
60
60
AsyncFunction("getStringArrayAsync") { (forKey: String) -> [String]? in
61
61
if let pref = userDefaults?.stringArray(forKey: forKey) {
62
62
return pref
63
63
}
64
64
return nil
65
65
}
66
-
67
-
AsyncFunction("setBoolAsync") { (forKey: String, value: Bool) -> Void in
66
+
67
+
AsyncFunction("setBoolAsync") { (forKey: String, value: Bool) in
68
68
userDefaults?.setValue(value, forKey: forKey)
69
69
}
70
-
71
-
AsyncFunction("setStringAsync") { (forKey: String, value: String) -> Void in
70
+
71
+
AsyncFunction("setStringAsync") { (forKey: String, value: String) in
72
72
userDefaults?.setValue(value, forKey: forKey)
73
73
}
74
-
75
-
AsyncFunction("setStringArrayAsync") { (forKey: String, value: [String]) -> Void in
74
+
75
+
AsyncFunction("setStringArrayAsync") { (forKey: String, value: [String]) in
76
76
userDefaults?.setValue(value, forKey: forKey)
77
77
}
78
-
78
+
79
79
AsyncFunction("addToStringArrayAsync") { (forKey: String, string: String) in
80
80
if var curr = userDefaults?.stringArray(forKey: forKey),
81
-
!curr.contains(string)
82
-
{
81
+
!curr.contains(string) {
83
82
curr.append(string)
84
83
userDefaults?.setValue(curr, forKey: forKey)
85
84
}
86
85
}
87
-
86
+
88
87
AsyncFunction("removeFromStringArrayAsync") { (forKey: String, string: String) in
89
88
if var curr = userDefaults?.stringArray(forKey: forKey) {
90
89
curr.removeAll { s in
···
93
92
userDefaults?.setValue(curr, forKey: forKey)
94
93
}
95
94
}
96
-
95
+
97
96
AsyncFunction("addManyToStringArrayAsync") { (forKey: String, strings: [String]) in
98
97
if var curr = userDefaults?.stringArray(forKey: forKey) {
99
98
strings.forEach { s in
···
104
103
userDefaults?.setValue(curr, forKey: forKey)
105
104
}
106
105
}
107
-
106
+
108
107
AsyncFunction("removeManyFromStringArrayAsync") { (forKey: String, strings: [String]) in
109
108
if var curr = userDefaults?.stringArray(forKey: forKey) {
110
109
strings.forEach { s in
···
113
112
userDefaults?.setValue(curr, forKey: forKey)
114
113
}
115
114
}
116
-
115
+
117
116
AsyncFunction("setBadgeCountAsync") { (count: Int) in
118
117
userDefaults?.setValue(count, forKey: "badgeCount")
119
118
}
+5
-2
modules/expo-bluesky-gif-view/android/src/main/java/expo/modules/blueskygifview/AppCompatImageViewExtended.kt
+5
-2
modules/expo-bluesky-gif-view/android/src/main/java/expo/modules/blueskygifview/AppCompatImageViewExtended.kt
···
5
5
import android.graphics.drawable.Animatable
6
6
import androidx.appcompat.widget.AppCompatImageView
7
7
8
-
class AppCompatImageViewExtended(context: Context, private val parent: GifView): AppCompatImageView(context) {
8
+
class AppCompatImageViewExtended(
9
+
context: Context,
10
+
private val parent: GifView,
11
+
) : AppCompatImageView(context) {
9
12
override fun onDraw(canvas: Canvas) {
10
13
super.onDraw(canvas)
11
14
···
34
37
drawable.start()
35
38
}
36
39
}
37
-
}
40
+
}
+34
-33
modules/expo-bluesky-gif-view/android/src/main/java/expo/modules/blueskygifview/ExpoBlueskyGifViewModule.kt
+34
-33
modules/expo-bluesky-gif-view/android/src/main/java/expo/modules/blueskygifview/ExpoBlueskyGifViewModule.kt
···
6
6
import expo.modules.kotlin.modules.ModuleDefinition
7
7
8
8
class ExpoBlueskyGifViewModule : Module() {
9
-
override fun definition() = ModuleDefinition {
10
-
Name("ExpoBlueskyGifView")
9
+
override fun definition() =
10
+
ModuleDefinition {
11
+
Name("ExpoBlueskyGifView")
11
12
12
-
AsyncFunction("prefetchAsync") { sources: List<String> ->
13
-
val activity = appContext.currentActivity ?: return@AsyncFunction
14
-
val glide = Glide.with(activity)
13
+
AsyncFunction("prefetchAsync") { sources: List<String> ->
14
+
val activity = appContext.currentActivity ?: return@AsyncFunction
15
+
val glide = Glide.with(activity)
15
16
16
-
sources.forEach { source ->
17
-
glide
18
-
.download(source)
19
-
.diskCacheStrategy(DiskCacheStrategy.DATA)
20
-
.submit()
17
+
sources.forEach { source ->
18
+
glide
19
+
.download(source)
20
+
.diskCacheStrategy(DiskCacheStrategy.DATA)
21
+
.submit()
22
+
}
21
23
}
22
-
}
23
24
24
-
View(GifView::class) {
25
-
Events(
26
-
"onPlayerStateChange"
27
-
)
25
+
View(GifView::class) {
26
+
Events(
27
+
"onPlayerStateChange",
28
+
)
28
29
29
-
Prop("source") { view: GifView, source: String ->
30
-
view.source = source
31
-
}
30
+
Prop("source") { view: GifView, source: String ->
31
+
view.source = source
32
+
}
32
33
33
-
Prop("placeholderSource") { view: GifView, source: String ->
34
-
view.placeholderSource = source
35
-
}
34
+
Prop("placeholderSource") { view: GifView, source: String ->
35
+
view.placeholderSource = source
36
+
}
36
37
37
-
Prop("autoplay") { view: GifView, autoplay: Boolean ->
38
-
view.autoplay = autoplay
39
-
}
38
+
Prop("autoplay") { view: GifView, autoplay: Boolean ->
39
+
view.autoplay = autoplay
40
+
}
40
41
41
-
AsyncFunction("playAsync") { view: GifView ->
42
-
view.play()
43
-
}
42
+
AsyncFunction("playAsync") { view: GifView ->
43
+
view.play()
44
+
}
44
45
45
-
AsyncFunction("pauseAsync") { view: GifView ->
46
-
view.pause()
47
-
}
46
+
AsyncFunction("pauseAsync") { view: GifView ->
47
+
view.pause()
48
+
}
48
49
49
-
AsyncFunction("toggleAsync") { view: GifView ->
50
-
view.toggle()
50
+
AsyncFunction("toggleAsync") { view: GifView ->
51
+
view.toggle()
52
+
}
51
53
}
52
54
}
53
-
}
54
55
}
+75
-70
modules/expo-bluesky-gif-view/android/src/main/java/expo/modules/blueskygifview/GifView.kt
+75
-70
modules/expo-bluesky-gif-view/android/src/main/java/expo/modules/blueskygifview/GifView.kt
···
1
1
package expo.modules.blueskygifview
2
2
3
-
4
3
import android.content.Context
5
4
import android.graphics.Color
6
5
import android.graphics.drawable.Animatable
···
15
14
import expo.modules.kotlin.viewevent.EventDispatcher
16
15
import expo.modules.kotlin.views.ExpoView
17
16
18
-
class GifView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
17
+
class GifView(
18
+
context: Context,
19
+
appContext: AppContext,
20
+
) : ExpoView(context, appContext) {
19
21
// Events
20
22
private val onPlayerStateChange by EventDispatcher()
21
23
···
44
46
}
45
47
}
46
48
47
-
48
-
//<editor-fold desc="Lifecycle">
49
+
// <editor-fold desc="Lifecycle">
49
50
50
51
init {
51
52
this.setBackgroundColor(Color.TRANSPARENT)
···
70
71
super.onDetachedFromWindow()
71
72
}
72
73
73
-
//</editor-fold>
74
+
// </editor-fold>
74
75
75
-
//<editor-fold desc="Loading">
76
+
// <editor-fold desc="Loading">
76
77
77
78
private fun load() {
78
79
if (placeholderSource == null || source == null) {
79
80
return
80
81
}
81
82
82
-
this.webpRequest = glide.load(source)
83
-
.diskCacheStrategy(DiskCacheStrategy.DATA)
84
-
.skipMemoryCache(false)
85
-
.listener(object: RequestListener<Drawable> {
86
-
override fun onResourceReady(
87
-
resource: Drawable?,
88
-
model: Any?,
89
-
target: Target<Drawable>?,
90
-
dataSource: com.bumptech.glide.load.DataSource?,
91
-
isFirstResource: Boolean
92
-
): Boolean {
93
-
if (placeholderRequest != null) {
94
-
glide.clear(placeholderRequest)
95
-
}
96
-
return false
97
-
}
83
+
this.webpRequest =
84
+
glide
85
+
.load(source)
86
+
.diskCacheStrategy(DiskCacheStrategy.DATA)
87
+
.skipMemoryCache(false)
88
+
.listener(
89
+
object : RequestListener<Drawable> {
90
+
override fun onResourceReady(
91
+
resource: Drawable?,
92
+
model: Any?,
93
+
target: Target<Drawable>?,
94
+
dataSource: com.bumptech.glide.load.DataSource?,
95
+
isFirstResource: Boolean,
96
+
): Boolean {
97
+
if (placeholderRequest != null) {
98
+
glide.clear(placeholderRequest)
99
+
}
100
+
return false
101
+
}
98
102
99
-
override fun onLoadFailed(
100
-
e: GlideException?,
101
-
model: Any?,
102
-
target: Target<Drawable>?,
103
-
isFirstResource: Boolean
104
-
): Boolean {
105
-
return true
106
-
}
107
-
})
108
-
.into(this.imageView)
103
+
override fun onLoadFailed(
104
+
e: GlideException?,
105
+
model: Any?,
106
+
target: Target<Drawable>?,
107
+
isFirstResource: Boolean,
108
+
): Boolean = true
109
+
},
110
+
).into(this.imageView)
109
111
110
112
if (this.imageView.drawable == null || this.imageView.drawable !is Animatable) {
111
-
this.placeholderRequest = glide.load(placeholderSource)
112
-
.diskCacheStrategy(DiskCacheStrategy.DATA)
113
-
// Let's not bloat the memory cache with placeholders
114
-
.skipMemoryCache(true)
115
-
.listener(object: RequestListener<Drawable> {
116
-
override fun onResourceReady(
117
-
resource: Drawable?,
118
-
model: Any?,
119
-
target: Target<Drawable>?,
120
-
dataSource: com.bumptech.glide.load.DataSource?,
121
-
isFirstResource: Boolean
122
-
): Boolean {
123
-
// Incase this request finishes after the webp, let's just not set
124
-
// the drawable. This shouldn't happen because the request should get cancelled
125
-
if (imageView.drawable == null) {
126
-
imageView.setImageDrawable(resource)
127
-
}
128
-
return true
129
-
}
113
+
this.placeholderRequest =
114
+
glide
115
+
.load(placeholderSource)
116
+
.diskCacheStrategy(DiskCacheStrategy.DATA)
117
+
// Let's not bloat the memory cache with placeholders
118
+
.skipMemoryCache(true)
119
+
.listener(
120
+
object : RequestListener<Drawable> {
121
+
override fun onResourceReady(
122
+
resource: Drawable?,
123
+
model: Any?,
124
+
target: Target<Drawable>?,
125
+
dataSource: com.bumptech.glide.load.DataSource?,
126
+
isFirstResource: Boolean,
127
+
): Boolean {
128
+
// Incase this request finishes after the webp, let's just not set
129
+
// the drawable. This shouldn't happen because the request should get cancelled
130
+
if (imageView.drawable == null) {
131
+
imageView.setImageDrawable(resource)
132
+
}
133
+
return true
134
+
}
130
135
131
-
override fun onLoadFailed(
132
-
e: GlideException?,
133
-
model: Any?,
134
-
target: Target<Drawable>?,
135
-
isFirstResource: Boolean
136
-
): Boolean {
137
-
return true
138
-
}
139
-
})
140
-
.submit()
136
+
override fun onLoadFailed(
137
+
e: GlideException?,
138
+
model: Any?,
139
+
target: Target<Drawable>?,
140
+
isFirstResource: Boolean,
141
+
): Boolean = true
142
+
},
143
+
).submit()
141
144
}
142
145
}
143
146
144
-
//</editor-fold>
147
+
// </editor-fold>
145
148
146
-
//<editor-fold desc="Controls">
149
+
// <editor-fold desc="Controls">
147
150
148
151
fun play() {
149
152
this.imageView.play()
···
165
168
}
166
169
}
167
170
168
-
//</editor-fold>
171
+
// </editor-fold>
169
172
170
-
//<editor-fold desc="Util">
173
+
// <editor-fold desc="Util">
171
174
172
175
fun firePlayerStateChange() {
173
-
onPlayerStateChange(mapOf(
174
-
"isPlaying" to this.isPlaying,
175
-
"isLoaded" to this.isLoaded,
176
-
))
176
+
onPlayerStateChange(
177
+
mapOf(
178
+
"isPlaying" to this.isPlaying,
179
+
"isLoaded" to this.isLoaded,
180
+
),
181
+
)
177
182
}
178
183
179
-
//</editor-fold>
184
+
// </editor-fold>
180
185
}
+8
-8
modules/expo-bluesky-gif-view/ios/ExpoBlueskyGifViewModule.swift
+8
-8
modules/expo-bluesky-gif-view/ios/ExpoBlueskyGifViewModule.swift
···
5
5
public class ExpoBlueskyGifViewModule: Module {
6
6
public func definition() -> ModuleDefinition {
7
7
Name("ExpoBlueskyGifView")
8
-
8
+
9
9
OnCreate {
10
10
SDImageCodersManager.shared.addCoder(SDImageGIFCoder.shared)
11
11
}
12
-
12
+
13
13
AsyncFunction("prefetchAsync") { (sources: [URL]) in
14
14
SDWebImagePrefetcher.shared.prefetchURLs(sources, context: Util.createContext(), progress: nil)
15
15
}
···
18
18
Events(
19
19
"onPlayerStateChange"
20
20
)
21
-
21
+
22
22
Prop("source") { (view: GifView, prop: String) in
23
23
view.source = prop
24
24
}
25
-
25
+
26
26
Prop("placeholderSource") { (view: GifView, prop: String) in
27
27
view.placeholderSource = prop
28
28
}
29
-
29
+
30
30
Prop("autoplay") { (view: GifView, prop: Bool) in
31
31
view.autoplay = prop
32
32
}
33
-
33
+
34
34
AsyncFunction("toggleAsync") { (view: GifView) in
35
35
view.toggle()
36
36
}
37
-
37
+
38
38
AsyncFunction("playAsync") { (view: GifView) in
39
39
view.play()
40
40
}
41
-
41
+
42
42
AsyncFunction("pauseAsync") { (view: GifView) in
43
43
view.pause()
44
44
}
+6
-9
modules/expo-bluesky-gif-view/ios/GifView.swift
+6
-9
modules/expo-bluesky-gif-view/ios/GifView.swift
···
16
16
)
17
17
private var isPlaying = true
18
18
private var isLoaded = false
19
-
19
+
20
20
// Requests
21
21
private var webpOperation: SDWebImageCombinedOperation?
22
22
private var placeholderOperation: SDWebImageCombinedOperation?
23
23
24
24
// Props
25
-
var source: String? = nil
26
-
var placeholderSource: String? = nil
25
+
var source: String?
26
+
var placeholderSource: String?
27
27
var autoplay = true {
28
28
didSet {
29
29
if !autoplay {
···
78
78
// See:
79
79
// https://github.com/SDWebImage/SDWebImage/blob/master/Docs/HowToUse.md#using-asynchronous-image-caching-independently
80
80
if !SDImageCache.shared.diskImageDataExists(withKey: source),
81
-
let url = URL(string: placeholderSource)
82
-
{
81
+
let url = URL(string: placeholderSource) {
83
82
self.placeholderOperation = imageManager.loadImage(
84
83
with: url,
85
84
options: [.retryFailed],
···
132
131
if let placeholderSource = self.placeholderSource,
133
132
imageUrl?.absoluteString == placeholderSource,
134
133
self.imageView.image == nil,
135
-
let image = image
136
-
{
134
+
let image = image {
137
135
self.setImage(image)
138
136
return
139
137
}
···
142
140
imageUrl?.absoluteString == source,
143
141
// UIImage perf suckssss if the image is animated
144
142
let data = data,
145
-
let animatedImage = SDAnimatedImage(data: data)
146
-
{
143
+
let animatedImage = SDAnimatedImage(data: data) {
147
144
self.placeholderOperation?.cancel()
148
145
self.isPlaying = self.autoplay
149
146
self.isLoaded = true
+4
-3
modules/expo-bluesky-swiss-army/android/src/main/java/expo/modules/blueskyswissarmy/deviceprefs/ExpoBlueskyDevicePrefsModule.kt
+4
-3
modules/expo-bluesky-swiss-army/android/src/main/java/expo/modules/blueskyswissarmy/deviceprefs/ExpoBlueskyDevicePrefsModule.kt
···
4
4
import expo.modules.kotlin.modules.ModuleDefinition
5
5
6
6
class ExpoBlueskyDevicePrefsModule : Module() {
7
-
override fun definition() = ModuleDefinition {
8
-
Name("ExpoBlueskyDevicePrefs")
9
-
}
7
+
override fun definition() =
8
+
ModuleDefinition {
9
+
Name("ExpoBlueskyDevicePrefs")
10
+
}
10
11
}
+43
-40
modules/expo-bluesky-swiss-army/android/src/main/java/expo/modules/blueskyswissarmy/referrer/ExpoBlueskyReferrerModule.kt
+43
-40
modules/expo-bluesky-swiss-army/android/src/main/java/expo/modules/blueskyswissarmy/referrer/ExpoBlueskyReferrerModule.kt
···
3
3
import android.util.Log
4
4
import com.android.installreferrer.api.InstallReferrerClient
5
5
import com.android.installreferrer.api.InstallReferrerStateListener
6
+
import expo.modules.kotlin.Promise
6
7
import expo.modules.kotlin.modules.Module
7
8
import expo.modules.kotlin.modules.ModuleDefinition
8
-
import expo.modules.kotlin.Promise
9
9
10
10
class ExpoBlueskyReferrerModule : Module() {
11
-
override fun definition() = ModuleDefinition {
12
-
Name("ExpoBlueskyReferrer")
11
+
override fun definition() =
12
+
ModuleDefinition {
13
+
Name("ExpoBlueskyReferrer")
13
14
14
-
AsyncFunction("getGooglePlayReferrerInfoAsync") { promise: Promise ->
15
-
val referrerClient = InstallReferrerClient.newBuilder(appContext.reactContext).build()
16
-
referrerClient.startConnection(object : InstallReferrerStateListener {
17
-
override fun onInstallReferrerSetupFinished(responseCode: Int) {
18
-
if (responseCode == InstallReferrerClient.InstallReferrerResponse.OK) {
19
-
Log.d("ExpoGooglePlayReferrer", "Successfully retrieved referrer info.")
15
+
AsyncFunction("getGooglePlayReferrerInfoAsync") { promise: Promise ->
16
+
val referrerClient = InstallReferrerClient.newBuilder(appContext.reactContext).build()
17
+
referrerClient.startConnection(
18
+
object : InstallReferrerStateListener {
19
+
override fun onInstallReferrerSetupFinished(responseCode: Int) {
20
+
if (responseCode == InstallReferrerClient.InstallReferrerResponse.OK) {
21
+
Log.d("ExpoGooglePlayReferrer", "Successfully retrieved referrer info.")
20
22
21
-
val response = referrerClient.installReferrer
22
-
Log.d("ExpoGooglePlayReferrer", "Install referrer: ${response.installReferrer}")
23
+
val response = referrerClient.installReferrer
24
+
Log.d("ExpoGooglePlayReferrer", "Install referrer: ${response.installReferrer}")
25
+
26
+
promise.resolve(
27
+
mapOf(
28
+
"installReferrer" to response.installReferrer,
29
+
"clickTimestamp" to response.referrerClickTimestampSeconds,
30
+
"installTimestamp" to response.installBeginTimestampSeconds,
31
+
),
32
+
)
33
+
} else {
34
+
Log.d("ExpoGooglePlayReferrer", "Failed to get referrer info. Unknown error.")
35
+
promise.reject(
36
+
"ERR_GOOGLE_PLAY_REFERRER_UNKNOWN",
37
+
"Failed to get referrer info",
38
+
Exception("Failed to get referrer info"),
39
+
)
40
+
}
41
+
referrerClient.endConnection()
42
+
}
23
43
24
-
promise.resolve(
25
-
mapOf(
26
-
"installReferrer" to response.installReferrer,
27
-
"clickTimestamp" to response.referrerClickTimestampSeconds,
28
-
"installTimestamp" to response.installBeginTimestampSeconds
44
+
override fun onInstallReferrerServiceDisconnected() {
45
+
Log.d("ExpoGooglePlayReferrer", "Failed to get referrer info. Service disconnected.")
46
+
referrerClient.endConnection()
47
+
promise.reject(
48
+
"ERR_GOOGLE_PLAY_REFERRER_DISCONNECTED",
49
+
"Failed to get referrer info",
50
+
Exception("Failed to get referrer info"),
29
51
)
30
-
)
31
-
} else {
32
-
Log.d("ExpoGooglePlayReferrer", "Failed to get referrer info. Unknown error.")
33
-
promise.reject(
34
-
"ERR_GOOGLE_PLAY_REFERRER_UNKNOWN",
35
-
"Failed to get referrer info",
36
-
Exception("Failed to get referrer info")
37
-
)
38
-
}
39
-
referrerClient.endConnection()
40
-
}
41
-
42
-
override fun onInstallReferrerServiceDisconnected() {
43
-
Log.d("ExpoGooglePlayReferrer", "Failed to get referrer info. Service disconnected.")
44
-
referrerClient.endConnection()
45
-
promise.reject(
46
-
"ERR_GOOGLE_PLAY_REFERRER_DISCONNECTED",
47
-
"Failed to get referrer info",
48
-
Exception("Failed to get referrer info")
49
-
)
50
-
}
51
-
})
52
+
}
53
+
},
54
+
)
55
+
}
52
56
}
53
-
}
54
-
}
57
+
}
+19
-17
modules/expo-receive-android-intents/android/src/main/java/xyz/blueskyweb/app/exporeceiveandroidintents/ExpoReceiveAndroidIntentsModule.kt
+19
-17
modules/expo-receive-android-intents/android/src/main/java/xyz/blueskyweb/app/exporeceiveandroidintents/ExpoReceiveAndroidIntentsModule.kt
···
13
13
import java.net.URLEncoder
14
14
15
15
class ExpoReceiveAndroidIntentsModule : Module() {
16
-
override fun definition() = ModuleDefinition {
17
-
Name("ExpoReceiveAndroidIntents")
16
+
override fun definition() =
17
+
ModuleDefinition {
18
+
Name("ExpoReceiveAndroidIntents")
18
19
19
-
OnNewIntent {
20
-
handleIntent(it)
20
+
OnNewIntent {
21
+
handleIntent(it)
22
+
}
21
23
}
22
-
}
23
24
24
25
private fun handleIntent(intent: Intent?) {
25
-
if(appContext.currentActivity == null || intent == null) return
26
+
if (appContext.currentActivity == null || intent == null) return
26
27
27
28
if (intent.action == Intent.ACTION_SEND) {
28
29
if (intent.type == "text/plain") {
···
40
41
private fun handleTextIntent(intent: Intent) {
41
42
intent.getStringExtra(Intent.EXTRA_TEXT)?.let {
42
43
val encoded = URLEncoder.encode(it, "UTF-8")
43
-
"bluesky://intent/compose?text=${encoded}".toUri().let { uri ->
44
+
"bluesky://intent/compose?text=$encoded".toUri().let { uri ->
44
45
val newIntent = Intent(Intent.ACTION_VIEW, uri)
45
46
appContext.currentActivity?.startActivity(newIntent)
46
47
}
···
48
49
}
49
50
50
51
private fun handleImageIntent(intent: Intent) {
51
-
val uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
52
-
intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
53
-
} else {
54
-
intent.getParcelableExtra(Intent.EXTRA_STREAM)
55
-
}
52
+
val uri =
53
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
54
+
intent.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java)
55
+
} else {
56
+
intent.getParcelableExtra(Intent.EXTRA_STREAM)
57
+
}
56
58
if (uri == null) return
57
59
58
60
handleImageIntents(listOf(uri))
···
76
78
uris.forEachIndexed { index, uri ->
77
79
val info = getImageInfo(uri)
78
80
val params = buildUriData(info)
79
-
allParams = "${allParams}${params}"
81
+
allParams = "${allParams}$params"
80
82
81
83
if (index < uris.count() - 1) {
82
-
allParams = "${allParams},"
84
+
allParams = "$allParams,"
83
85
}
84
86
}
85
87
86
88
val encoded = URLEncoder.encode(allParams, "UTF-8")
87
89
88
-
"bluesky://intent/compose?imageUris=${encoded}".toUri().let {
90
+
"bluesky://intent/compose?imageUris=$encoded".toUri().let {
89
91
val newIntent = Intent(Intent.ACTION_VIEW, it)
90
92
appContext.currentActivity?.startActivity(newIntent)
91
93
}
···
104
106
return mapOf(
105
107
"width" to bitmap.width,
106
108
"height" to bitmap.height,
107
-
"path" to file.path.toString()
109
+
"path" to file.path.toString(),
108
110
)
109
111
}
110
112
···
114
116
val path = info.getValue("path")
115
117
val width = info.getValue("width")
116
118
val height = info.getValue("height")
117
-
return "file://${path}|${width}|${height}"
119
+
return "file://$path|$width|$height"
118
120
}
119
121
}
+1
-1
modules/expo-scroll-forwarder/ios/ExpoScrollForwarderModule.swift
+1
-1
modules/expo-scroll-forwarder/ios/ExpoScrollForwarderModule.swift
+37
-39
modules/expo-scroll-forwarder/ios/ExpoScrollForwarderView.swift
+37
-39
modules/expo-scroll-forwarder/ios/ExpoScrollForwarderView.swift
···
8
8
self.tryFindScrollView()
9
9
}
10
10
}
11
-
11
+
12
12
private var rctScrollView: RCTScrollView?
13
13
private var rctRefreshCtrl: RCTRefreshControl?
14
14
private var cancelGestureRecognizers: [UIGestureRecognizer]?
15
15
private var animTimer: Timer?
16
16
private var initialOffset: CGFloat = 0.0
17
17
private var didImpact: Bool = false
18
-
18
+
19
19
required init(appContext: AppContext? = nil) {
20
20
super.init(appContext: appContext)
21
-
21
+
22
22
let pg = UIPanGestureRecognizer(target: self, action: #selector(callOnPan(_:)))
23
23
pg.delegate = self
24
24
self.addGestureRecognizer(pg)
···
34
34
35
35
self.cancelGestureRecognizers = [lpg, tg]
36
36
}
37
-
38
37
39
38
// We don't want to recognize the scroll pan gesture and the swipe back gesture together
40
39
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
41
40
if gestureRecognizer is UIPanGestureRecognizer, otherGestureRecognizer is UIPanGestureRecognizer {
42
41
return false
43
42
}
44
-
43
+
45
44
return true
46
45
}
47
-
46
+
48
47
// We only want the "scroll" gesture to happen whenever the pan is vertical, otherwise it will
49
48
// interfere with the native swipe back gesture.
50
49
override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
51
50
guard let gestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer else {
52
51
return true
53
52
}
54
-
53
+
55
54
let velocity = gestureRecognizer.velocity(in: self)
56
55
return abs(velocity.y) > abs(velocity.x)
57
56
}
58
-
57
+
59
58
// This will be used to cancel the scroll animation whenever we tap inside of the header. We don't need another
60
59
// recognizer for this one.
61
60
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
···
64
63
65
64
// This will be used to cancel the animation whenever we press inside of the scroll view. We don't want to change
66
65
// the scroll view gesture's delegate, so we add an additional recognizer to detect this.
67
-
@IBAction func callOnPress(_ sender: UITapGestureRecognizer) -> Void {
66
+
@IBAction func callOnPress(_ sender: UITapGestureRecognizer) {
68
67
self.stopTimer()
69
68
}
70
-
71
-
@IBAction func callOnPan(_ sender: UIPanGestureRecognizer) -> Void {
69
+
70
+
@IBAction func callOnPan(_ sender: UIPanGestureRecognizer) {
72
71
guard let rctsv = self.rctScrollView, let sv = rctsv.scrollView else {
73
72
return
74
73
}
75
74
76
75
let translation = sender.translation(in: self).y
77
-
76
+
78
77
if sender.state == .began {
79
78
if sv.contentOffset.y < 0 {
80
79
sv.contentOffset.y = 0
81
80
}
82
-
81
+
83
82
self.initialOffset = sv.contentOffset.y
84
83
}
85
84
86
85
if sender.state == .changed {
87
86
sv.contentOffset.y = self.dampenOffset(-translation + self.initialOffset)
88
-
87
+
89
88
if sv.contentOffset.y <= -130, !didImpact {
90
89
let generator = UIImpactFeedbackGenerator(style: .light)
91
90
generator.impactOccurred()
92
-
91
+
93
92
self.didImpact = true
94
93
}
95
94
}
···
97
96
if sender.state == .ended {
98
97
let velocity = sender.velocity(in: self).y
99
98
self.didImpact = false
100
-
99
+
101
100
if sv.contentOffset.y <= -130 {
102
101
self.rctRefreshCtrl?.forwarderBeginRefreshing()
103
102
return
···
108
107
if abs(velocity) < 250, sv.contentOffset.y >= 0 {
109
108
return
110
109
}
111
-
110
+
112
111
self.startDecayAnimation(translation, velocity)
113
112
}
114
113
}
115
-
114
+
116
115
func startDecayAnimation(_ translation: CGFloat, _ velocity: CGFloat) {
117
116
guard let sv = self.rctScrollView?.scrollView else {
118
117
return
119
118
}
120
-
119
+
121
120
var velocity = velocity
122
-
121
+
123
122
self.enableCancelGestureRecognizers()
124
-
123
+
125
124
if velocity > 0 {
126
125
velocity = min(velocity, 5000)
127
126
} else {
128
127
velocity = max(velocity, -5000)
129
128
}
130
-
129
+
131
130
var animTranslation = -translation
132
-
self.animTimer = Timer.scheduledTimer(withTimeInterval: 1.0 / 120, repeats: true) { timer in
131
+
self.animTimer = Timer.scheduledTimer(withTimeInterval: 1.0 / 120, repeats: true) { _ in
133
132
velocity *= 0.9875
134
133
animTranslation = (-velocity / 120) + animTranslation
135
-
134
+
136
135
let nextOffset = self.dampenOffset(animTranslation + self.initialOffset)
137
-
136
+
138
137
if nextOffset <= 0 {
139
138
if self.initialOffset <= 1 {
140
139
self.scrollToOffset(0)
141
140
} else {
142
141
sv.contentOffset.y = 0
143
142
}
144
-
143
+
145
144
self.stopTimer()
146
145
return
147
146
} else {
···
153
152
}
154
153
}
155
154
}
156
-
155
+
157
156
func dampenOffset(_ offset: CGFloat) -> CGFloat {
158
157
if offset < 0 {
159
158
return offset - (offset * 0.55)
160
159
}
161
-
160
+
162
161
return offset
163
162
}
164
-
163
+
165
164
func tryFindScrollView() {
166
165
guard let scrollViewTag = scrollViewTag else {
167
166
return
168
167
}
169
-
168
+
170
169
// Before we switch to a different scrollview, we always want to remove the cancel gesture recognizer.
171
170
// Otherwise we might end up with duplicates when we switch back to that scrollview.
172
171
self.removeCancelGestureRecognizers()
173
-
172
+
174
173
self.rctScrollView = self.appContext?
175
174
.findView(withTag: scrollViewTag, ofType: RCTScrollView.self)
176
175
self.rctRefreshCtrl = self.rctScrollView?.scrollView.refreshControl as? RCTRefreshControl
177
-
176
+
178
177
self.addCancelGestureRecognizers()
179
178
}
180
-
179
+
181
180
func addCancelGestureRecognizers() {
182
181
self.cancelGestureRecognizers?.forEach { r in
183
182
self.rctScrollView?.scrollView?.addGestureRecognizer(r)
184
183
}
185
184
}
186
-
185
+
187
186
func removeCancelGestureRecognizers() {
188
187
self.cancelGestureRecognizers?.forEach { r in
189
188
self.rctScrollView?.scrollView?.removeGestureRecognizer(r)
190
189
}
191
190
}
192
191
193
-
194
192
func enableCancelGestureRecognizers() {
195
193
self.cancelGestureRecognizers?.forEach { r in
196
194
r.isEnabled = true
197
195
}
198
196
}
199
-
197
+
200
198
func disableCancelGestureRecognizers() {
201
199
self.cancelGestureRecognizers?.forEach { r in
202
200
r.isEnabled = false
203
201
}
204
202
}
205
-
206
-
func scrollToOffset(_ offset: Int, animated: Bool = true) -> Void {
203
+
204
+
func scrollToOffset(_ offset: Int, animated: Bool = true) {
207
205
self.rctScrollView?.scroll(toOffset: CGPoint(x: 0, y: offset), animated: animated)
208
206
}
209
207
210
-
func stopTimer() -> Void {
208
+
func stopTimer() {
211
209
self.disableCancelGestureRecognizers()
212
210
self.animTimer?.invalidate()
213
211
self.animTimer = nil
+2
package.json
+2
package.json
···
29
29
"test-ci": "NODE_ENV=test jest --ci --forceExit --reporters=default --reporters=jest-junit",
30
30
"test-coverage": "NODE_ENV=test jest --coverage",
31
31
"lint": "eslint --cache --ext .js,.jsx,.ts,.tsx src",
32
+
"lint-native": "swiftlint ./modules && ktlint ./modules",
33
+
"lint-native:fix": "swiftlint --fix ./modules && ktlint --format ./modules",
32
34
"typecheck": "tsc --project ./tsconfig.check.json",
33
35
"e2e:mock-server": "./jest/dev-infra/with-test-redis-and-db.sh ts-node --project tsconfig.e2e.json __e2e__/mock-server.ts",
34
36
"e2e:metro": "EXPO_PUBLIC_ENV=e2e NODE_ENV=test RN_SRC_EXT=e2e.ts,e2e.tsx expo run:ios",