mirror of https://github.com/tooot-app/app
Merge branch 'main' into release
This commit is contained in:
commit
c46f03ed37
|
@ -1,363 +0,0 @@
|
||||||
diff --git a/RNFastImage.podspec b/RNFastImage.podspec
|
|
||||||
index db0fada63fc06191f8620d336d244edde6c3dba3..9c22c36f6978530da21afe143324ff79b4e96454 100644
|
|
||||||
--- a/RNFastImage.podspec
|
|
||||||
+++ b/RNFastImage.podspec
|
|
||||||
@@ -16,6 +16,6 @@ Pod::Spec.new do |s|
|
|
||||||
s.source_files = "ios/**/*.{h,m}"
|
|
||||||
|
|
||||||
s.dependency 'React-Core'
|
|
||||||
- s.dependency 'SDWebImage', '~> 5.11.1'
|
|
||||||
- s.dependency 'SDWebImageWebPCoder', '~> 0.8.4'
|
|
||||||
+ s.dependency 'SDWebImage', '~> 5.15.0'
|
|
||||||
+ s.dependency 'SDWebImageWebPCoder', '~> 0.9.1'
|
|
||||||
end
|
|
||||||
diff --git a/android/build.gradle b/android/build.gradle
|
|
||||||
index 5b21cd59c40a5754f5d19c77e2a0eb0229925911..19d82f826e88125c5e6d87ee7c348fac621f548c 100644
|
|
||||||
--- a/android/build.gradle
|
|
||||||
+++ b/android/build.gradle
|
|
||||||
@@ -65,4 +65,5 @@ dependencies {
|
|
||||||
implementation "com.github.bumptech.glide:glide:${glideVersion}"
|
|
||||||
implementation "com.github.bumptech.glide:okhttp3-integration:${glideVersion}"
|
|
||||||
annotationProcessor "com.github.bumptech.glide:compiler:${glideVersion}"
|
|
||||||
+ implementation 'com.github.penfeizhou.android.animation:glide-plugin:2.12.0'
|
|
||||||
}
|
|
||||||
diff --git a/android/src/main/java/com/dylanvann/fastimage/FastImageEnterTransition.java b/android/src/main/java/com/dylanvann/fastimage/FastImageEnterTransition.java
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..55e3b4e0d463654f62d942ba05c2a5e51ae9d6d7
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/android/src/main/java/com/dylanvann/fastimage/FastImageEnterTransition.java
|
|
||||||
@@ -0,0 +1,6 @@
|
|
||||||
+package com.dylanvann.fastimage;
|
|
||||||
+
|
|
||||||
+public enum FastImageEnterTransition {
|
|
||||||
+ TRANSITION_NONE,
|
|
||||||
+ FADE_IN
|
|
||||||
+}
|
|
||||||
diff --git a/android/src/main/java/com/dylanvann/fastimage/FastImageTransitions.java b/android/src/main/java/com/dylanvann/fastimage/FastImageTransitions.java
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..d764cc4b8d110f087120a4f0dc5d986754806dec
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/android/src/main/java/com/dylanvann/fastimage/FastImageTransitions.java
|
|
||||||
@@ -0,0 +1,20 @@
|
|
||||||
+package com.dylanvann.fastimage;
|
|
||||||
+
|
|
||||||
+import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions;
|
|
||||||
+import com.bumptech.glide.TransitionOptions;
|
|
||||||
+import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
|
||||||
+import android.view.animation.DecelerateInterpolator;
|
|
||||||
+
|
|
||||||
+public class FastImageTransitions {
|
|
||||||
+ static final DecelerateInterpolator mInterpolator = new DecelerateInterpolator();
|
|
||||||
+
|
|
||||||
+ public static TransitionOptions getEnterTransition(FastImageEnterTransition transition, int duration) {
|
|
||||||
+ switch (transition) {
|
|
||||||
+ case FADE_IN:
|
|
||||||
+ return DrawableTransitionOptions.withCrossFade(duration);
|
|
||||||
+
|
|
||||||
+ default:
|
|
||||||
+ throw new JSApplicationIllegalArgumentException("FastImage, invalid enterTransition argument");
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
\ No newline at end of file
|
|
||||||
diff --git a/android/src/main/java/com/dylanvann/fastimage/FastImageViewConverter.java b/android/src/main/java/com/dylanvann/fastimage/FastImageViewConverter.java
|
|
||||||
index 86ca00d018d7ded0edff733373d80976c8dbb961..e6220f57b38a3fe3ae9d5a75228f791e0ec978bb 100644
|
|
||||||
--- a/android/src/main/java/com/dylanvann/fastimage/FastImageViewConverter.java
|
|
||||||
+++ b/android/src/main/java/com/dylanvann/fastimage/FastImageViewConverter.java
|
|
||||||
@@ -50,6 +50,12 @@ class FastImageViewConverter {
|
|
||||||
put("center", ScaleType.CENTER_INSIDE);
|
|
||||||
}};
|
|
||||||
|
|
||||||
+ private static final Map<String, FastImageEnterTransition> FAST_IMAGE_ENTER_TRANSITION_MAP =
|
|
||||||
+ new HashMap<String, FastImageEnterTransition>() {{
|
|
||||||
+ put("none", FastImageEnterTransition.TRANSITION_NONE);
|
|
||||||
+ put("fadeIn", FastImageEnterTransition.FADE_IN);
|
|
||||||
+ }};
|
|
||||||
+
|
|
||||||
// Resolve the source uri to a file path that android understands.
|
|
||||||
static @Nullable
|
|
||||||
FastImageSource getImageSource(Context context, @Nullable ReadableMap source) {
|
|
||||||
@@ -125,6 +131,10 @@ class FastImageViewConverter {
|
|
||||||
return getValueFromSource("cache", "immutable", FAST_IMAGE_CACHE_CONTROL_MAP, source);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ static FastImageEnterTransition getEnterTransition(String propValue) {
|
|
||||||
+ return getValue("enterTransition", "none", FAST_IMAGE_ENTER_TRANSITION_MAP, propValue);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
private static Priority getPriority(ReadableMap source) {
|
|
||||||
return getValueFromSource("priority", "normal", FAST_IMAGE_PRIORITY_MAP, source);
|
|
||||||
}
|
|
||||||
diff --git a/android/src/main/java/com/dylanvann/fastimage/FastImageViewManager.java b/android/src/main/java/com/dylanvann/fastimage/FastImageViewManager.java
|
|
||||||
index c7a795471c8f8b48163c778836406bc5ead75dab..53b481547b44224e7791a8d3f39815c9c9a4be59 100644
|
|
||||||
--- a/android/src/main/java/com/dylanvann/fastimage/FastImageViewManager.java
|
|
||||||
+++ b/android/src/main/java/com/dylanvann/fastimage/FastImageViewManager.java
|
|
||||||
@@ -83,6 +83,17 @@ class FastImageViewManager extends SimpleViewManager<FastImageViewWithUrl> imple
|
|
||||||
view.setScaleType(scaleType);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ @ReactProp(name = "enterTransition")
|
|
||||||
+ public void setEnterTransition(FastImageViewWithUrl view, String enterTransition) {
|
|
||||||
+ final FastImageEnterTransition transition = FastImageViewConverter.getEnterTransition(enterTransition);
|
|
||||||
+ view.setEnterTransition(transition);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @ReactProp(name = "transitionDuration")
|
|
||||||
+ public void setTransitionDuration(FastImageViewWithUrl view, int transitionDuration) {
|
|
||||||
+ view.setTransitionDuration(transitionDuration);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
@Override
|
|
||||||
public void onDropViewInstance(@NonNull FastImageViewWithUrl view) {
|
|
||||||
// This will cancel existing requests.
|
|
||||||
diff --git a/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java b/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java
|
|
||||||
index 34fcf898d17d82fd52375e9028b71ad815b9b15b..fd57ac68de093d2a8ee53aeede45328c8d52aa39 100644
|
|
||||||
--- a/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java
|
|
||||||
+++ b/android/src/main/java/com/dylanvann/fastimage/FastImageViewWithUrl.java
|
|
||||||
@@ -30,6 +30,8 @@ class FastImageViewWithUrl extends AppCompatImageView {
|
|
||||||
private boolean mNeedsReload = false;
|
|
||||||
private ReadableMap mSource = null;
|
|
||||||
private Drawable mDefaultSource = null;
|
|
||||||
+ private FastImageEnterTransition mEnterTransition = FastImageEnterTransition.TRANSITION_NONE;
|
|
||||||
+ private int mTransitionDuration = 350;
|
|
||||||
|
|
||||||
public GlideUrl glideUrl;
|
|
||||||
|
|
||||||
@@ -47,6 +49,14 @@ class FastImageViewWithUrl extends AppCompatImageView {
|
|
||||||
mDefaultSource = source;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ public void setEnterTransition(@Nullable FastImageEnterTransition transition) {
|
|
||||||
+ mEnterTransition = transition;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ public void setTransitionDuration(int duration) {
|
|
||||||
+ mTransitionDuration = duration == 0 ? 350 : duration;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
private boolean isNullOrEmpty(final String url) {
|
|
||||||
return url == null || url.trim().isEmpty();
|
|
||||||
}
|
|
||||||
@@ -147,6 +157,10 @@ class FastImageViewWithUrl extends AppCompatImageView {
|
|
||||||
if (key != null)
|
|
||||||
builder.listener(new FastImageRequestListener(key));
|
|
||||||
|
|
||||||
+ if (mEnterTransition != FastImageEnterTransition.TRANSITION_NONE) {
|
|
||||||
+ builder.transition(FastImageTransitions.getEnterTransition(mEnterTransition, mTransitionDuration));
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
builder.into(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
diff --git a/dist/index.cjs.js b/dist/index.cjs.js
|
|
||||||
index 2df6a29769978d8d947dfb50b422e1f56bd97fb6..f3904e20edac5f19cc26f41a4ff02eecd73ac627 100644
|
|
||||||
--- a/dist/index.cjs.js
|
|
||||||
+++ b/dist/index.cjs.js
|
|
||||||
@@ -9,6 +9,10 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
|
|
||||||
var _extends__default = /*#__PURE__*/_interopDefaultLegacy(_extends);
|
|
||||||
var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
|
|
||||||
|
|
||||||
+const enterTransition = {
|
|
||||||
+ none: 'none',
|
|
||||||
+ fadeIn: 'fadeIn'
|
|
||||||
+}
|
|
||||||
const resizeMode = {
|
|
||||||
contain: 'contain',
|
|
||||||
cover: 'cover',
|
|
||||||
@@ -115,6 +119,7 @@ const FastImageComponent = /*#__PURE__*/React.forwardRef((props, ref) => /*#__PU
|
|
||||||
}, props)));
|
|
||||||
FastImageComponent.displayName = 'FastImage';
|
|
||||||
const FastImage = FastImageComponent;
|
|
||||||
+FastImage.enterTransition = enterTransition
|
|
||||||
FastImage.resizeMode = resizeMode;
|
|
||||||
FastImage.cacheControl = cacheControl;
|
|
||||||
FastImage.priority = priority;
|
|
||||||
diff --git a/dist/index.d.ts b/dist/index.d.ts
|
|
||||||
index 5abb7c98b767cd0709b53f5ab2dd50c752a9377b..2da22817e3136673d40a177ae8c9fc2209f143d8 100644
|
|
||||||
--- a/dist/index.d.ts
|
|
||||||
+++ b/dist/index.d.ts
|
|
||||||
@@ -1,5 +1,10 @@
|
|
||||||
import React from 'react';
|
|
||||||
import { FlexStyle, LayoutChangeEvent, ShadowStyleIOS, StyleProp, TransformsStyle, ImageRequireSource, AccessibilityProps, ViewProps, ColorValue } from 'react-native';
|
|
||||||
+export declare type EnterTransition = 'none' | 'fadeIn';
|
|
||||||
+declare const enterTransition: {
|
|
||||||
+ readonly none: "none";
|
|
||||||
+ readonly fadeIn: "fadeIn";
|
|
||||||
+};
|
|
||||||
export declare type ResizeMode = 'contain' | 'cover' | 'stretch' | 'center';
|
|
||||||
declare const resizeMode: {
|
|
||||||
readonly contain: "contain";
|
|
||||||
@@ -57,6 +62,16 @@ export interface FastImageProps extends AccessibilityProps, ViewProps {
|
|
||||||
defaultSource?: ImageRequireSource;
|
|
||||||
resizeMode?: ResizeMode;
|
|
||||||
fallback?: boolean;
|
|
||||||
+ /**
|
|
||||||
+ * Transition durations.
|
|
||||||
+ * @default none
|
|
||||||
+ */
|
|
||||||
+ enterTransition?: EnterTransition
|
|
||||||
+ /**
|
|
||||||
+ * Enter transition duration in ms.
|
|
||||||
+ * @default 500ms
|
|
||||||
+ */
|
|
||||||
+ transitionDuration?: number
|
|
||||||
onLoadStart?(): void;
|
|
||||||
onProgress?(event: OnProgressEvent): void;
|
|
||||||
onLoad?(event: OnLoadEvent): void;
|
|
||||||
@@ -91,6 +106,7 @@ export interface FastImageProps extends AccessibilityProps, ViewProps {
|
|
||||||
children?: React.ReactNode;
|
|
||||||
}
|
|
||||||
export interface FastImageStaticProperties {
|
|
||||||
+ enterTransition: typeof enterTransition;
|
|
||||||
resizeMode: typeof resizeMode;
|
|
||||||
priority: typeof priority;
|
|
||||||
cacheControl: typeof cacheControl;
|
|
||||||
diff --git a/dist/index.js b/dist/index.js
|
|
||||||
index 58e0308bd44836aad3e4979b5c1151083956c295..5853b3b2fd05c91be8c70819fe6fc45606f26f8d 100644
|
|
||||||
--- a/dist/index.js
|
|
||||||
+++ b/dist/index.js
|
|
||||||
@@ -2,6 +2,10 @@ import _extends from '@babel/runtime/helpers/extends';
|
|
||||||
import React, { forwardRef, memo } from 'react';
|
|
||||||
import { NativeModules, StyleSheet, requireNativeComponent, Image, View, Platform } from 'react-native';
|
|
||||||
|
|
||||||
+const enterTransition = {
|
|
||||||
+ none: 'none',
|
|
||||||
+ fadeIn: 'fadeIn'
|
|
||||||
+}
|
|
||||||
const resizeMode = {
|
|
||||||
contain: 'contain',
|
|
||||||
cover: 'cover',
|
|
||||||
@@ -57,6 +61,8 @@ function FastImageBase({
|
|
||||||
children,
|
|
||||||
// eslint-disable-next-line no-shadow
|
|
||||||
resizeMode = 'cover',
|
|
||||||
+ enterTransition = 'none',
|
|
||||||
+ transitionDuration = 350,
|
|
||||||
forwardedRef,
|
|
||||||
...props
|
|
||||||
}) {
|
|
||||||
@@ -79,7 +85,9 @@ function FastImageBase({
|
|
||||||
onLoad: onLoad,
|
|
||||||
onError: onError,
|
|
||||||
onLoadEnd: onLoadEnd,
|
|
||||||
- resizeMode: resizeMode
|
|
||||||
+ resizeMode: resizeMode,
|
|
||||||
+ enterTransition: enterTransition,
|
|
||||||
+ transitionDuration: transitionDuration
|
|
||||||
})), children);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -98,7 +106,9 @@ function FastImageBase({
|
|
||||||
onFastImageLoad: onLoad,
|
|
||||||
onFastImageError: onError,
|
|
||||||
onFastImageLoadEnd: onLoadEnd,
|
|
||||||
- resizeMode: resizeMode
|
|
||||||
+ resizeMode: resizeMode,
|
|
||||||
+ enterTransition: enterTransition,
|
|
||||||
+ transitionDuration: transitionDuration
|
|
||||||
})), children);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -108,6 +118,7 @@ const FastImageComponent = /*#__PURE__*/forwardRef((props, ref) => /*#__PURE__*/
|
|
||||||
}, props)));
|
|
||||||
FastImageComponent.displayName = 'FastImage';
|
|
||||||
const FastImage = FastImageComponent;
|
|
||||||
+FastImage.enterTransition = enterTransition
|
|
||||||
FastImage.resizeMode = resizeMode;
|
|
||||||
FastImage.cacheControl = cacheControl;
|
|
||||||
FastImage.priority = priority;
|
|
||||||
diff --git a/ios/FastImage/FFFastImageView.h b/ios/FastImage/FFFastImageView.h
|
|
||||||
index e52fca79882ad2a678487a46b2fe158427e06f3a..6c9c41b0b1a3c967a3715a24bb692447b76ef365 100644
|
|
||||||
--- a/ios/FastImage/FFFastImageView.h
|
|
||||||
+++ b/ios/FastImage/FFFastImageView.h
|
|
||||||
@@ -7,6 +7,7 @@
|
|
||||||
#import <React/RCTResizeMode.h>
|
|
||||||
|
|
||||||
#import "FFFastImageSource.h"
|
|
||||||
+#import "FFFastImageViewManager.h"
|
|
||||||
|
|
||||||
@interface FFFastImageView : SDAnimatedImageView
|
|
||||||
|
|
||||||
@@ -16,6 +17,8 @@
|
|
||||||
@property (nonatomic, copy) RCTDirectEventBlock onFastImageLoad;
|
|
||||||
@property (nonatomic, copy) RCTDirectEventBlock onFastImageLoadEnd;
|
|
||||||
@property (nonatomic, assign) RCTResizeMode resizeMode;
|
|
||||||
+@property (nonatomic, assign) FFFEnterTransition enterTransition;
|
|
||||||
+@property (nonatomic, assign) NSTimeInterval transitionDuration;
|
|
||||||
@property (nonatomic, strong) FFFastImageSource *source;
|
|
||||||
@property (nonatomic, strong) UIImage *defaultSource;
|
|
||||||
@property (nonatomic, strong) UIColor *imageColor;
|
|
||||||
diff --git a/ios/FastImage/FFFastImageView.m b/ios/FastImage/FFFastImageView.m
|
|
||||||
index f7100815e652539b29b1fa70ff1477c5f5db08dc..ecb79eafe566fe52090adada3cdf16eb10a67513 100644
|
|
||||||
--- a/ios/FastImage/FFFastImageView.m
|
|
||||||
+++ b/ios/FastImage/FFFastImageView.m
|
|
||||||
@@ -71,6 +71,18 @@ - (void) setImageColor: (UIColor*)imageColor {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+- (void) setTransitionDuration: (NSTimeInterval)transitionDuration {
|
|
||||||
+ self.sd_imageTransition.duration = transitionDuration;
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+- (void) setEnterTransition: (FFFEnterTransition)enterTransition {
|
|
||||||
+ switch (enterTransition) {
|
|
||||||
+ case FFFFadeIn:
|
|
||||||
+ self.sd_imageTransition = SDWebImageTransition.fadeTransition;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
- (UIImage*) makeImage: (UIImage*)image withTint: (UIColor*)color {
|
|
||||||
UIImage* newImage = [image imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate];
|
|
||||||
UIGraphicsBeginImageContextWithOptions(image.size, NO, newImage.scale);
|
|
||||||
diff --git a/ios/FastImage/FFFastImageViewManager.h b/ios/FastImage/FFFastImageViewManager.h
|
|
||||||
index 8ba6020e2c6e5757ed778d00e3f43a6ff4c1d50a..a269669301ea00ef3c2714123d17e822094635d6 100644
|
|
||||||
--- a/ios/FastImage/FFFastImageViewManager.h
|
|
||||||
+++ b/ios/FastImage/FFFastImageViewManager.h
|
|
||||||
@@ -1,5 +1,10 @@
|
|
||||||
#import <React/RCTViewManager.h>
|
|
||||||
|
|
||||||
+typedef NS_ENUM(NSInteger, FFFEnterTransition) {
|
|
||||||
+ FFFTransitionNone,
|
|
||||||
+ FFFFadeIn,
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
@interface FFFastImageViewManager : RCTViewManager
|
|
||||||
|
|
||||||
@end
|
|
||||||
diff --git a/ios/FastImage/FFFastImageViewManager.m b/ios/FastImage/FFFastImageViewManager.m
|
|
||||||
index 84ca94e26e546d4d139dabca6c3efd0a890eda63..2184bac31f0d547e6119356bb4fc7931be87446d 100644
|
|
||||||
--- a/ios/FastImage/FFFastImageViewManager.m
|
|
||||||
+++ b/ios/FastImage/FFFastImageViewManager.m
|
|
||||||
@@ -13,6 +13,8 @@ - (FFFastImageView*)view {
|
|
||||||
}
|
|
||||||
|
|
||||||
RCT_EXPORT_VIEW_PROPERTY(source, FFFastImageSource)
|
|
||||||
+RCT_EXPORT_VIEW_PROPERTY(enterTransition, FFFEnterTransition)
|
|
||||||
+RCT_EXPORT_VIEW_PROPERTY(transitionDuration, NSTimeInterval)
|
|
||||||
RCT_EXPORT_VIEW_PROPERTY(defaultSource, UIImage)
|
|
||||||
RCT_EXPORT_VIEW_PROPERTY(resizeMode, RCTResizeMode)
|
|
||||||
RCT_EXPORT_VIEW_PROPERTY(onFastImageLoadStart, RCTDirectEventBlock)
|
|
||||||
diff --git a/ios/FastImage/RCTConvert+FFFastImage.m b/ios/FastImage/RCTConvert+FFFastImage.m
|
|
||||||
index 43f8922157655a7497f56a3909ef6b2a886f07d8..0705f8e05f44f3053e7239fcc9a30d986e7aaab7 100644
|
|
||||||
--- a/ios/FastImage/RCTConvert+FFFastImage.m
|
|
||||||
+++ b/ios/FastImage/RCTConvert+FFFastImage.m
|
|
||||||
@@ -1,5 +1,6 @@
|
|
||||||
#import "RCTConvert+FFFastImage.h"
|
|
||||||
#import "FFFastImageSource.h"
|
|
||||||
+#import "FFFastImageViewManager.h"
|
|
||||||
|
|
||||||
@implementation RCTConvert (FFFastImage)
|
|
||||||
|
|
||||||
@@ -15,6 +16,11 @@ @implementation RCTConvert (FFFastImage)
|
|
||||||
@"cacheOnly": @(FFFCacheControlCacheOnly),
|
|
||||||
}), FFFCacheControlImmutable, integerValue);
|
|
||||||
|
|
||||||
+RCT_ENUM_CONVERTER(FFFEnterTransition, (@{
|
|
||||||
+ @"none": @(FFFTransitionNone),
|
|
||||||
+ @"fadeIn": @(FFFFadeIn),
|
|
||||||
+ }), FFFTransitionNone, integerValue);
|
|
||||||
+
|
|
||||||
+ (FFFastImageSource *)FFFastImageSource:(id)json {
|
|
||||||
if (!json) {
|
|
||||||
return nil;
|
|
|
@ -3,14 +3,14 @@ PODS:
|
||||||
- DoubleConversion (1.1.6)
|
- DoubleConversion (1.1.6)
|
||||||
- EXApplication (5.0.1):
|
- EXApplication (5.0.1):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- EXAV (13.1.0):
|
- EXAV (13.2.0):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- ReactCommon/turbomodule/core
|
- ReactCommon/turbomodule/core
|
||||||
- EXConstants (14.1.0):
|
- EXConstants (14.2.0):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- EXErrorRecovery (4.0.1):
|
- EXErrorRecovery (4.0.1):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- EXFileSystem (15.1.1):
|
- EXFileSystem (15.2.0):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- EXFont (11.0.1):
|
- EXFont (11.0.1):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
|
@ -18,31 +18,37 @@ PODS:
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- Expo (47.0.13):
|
- Expo (47.0.13):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- ExpoCrypto (12.1.0):
|
- ExpoCrypto (12.2.0):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- ExpoHaptics (12.1.0):
|
- ExpoHaptics (12.2.0):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
|
- ExpoImage (1.0.0-beta.6):
|
||||||
|
- ExpoModulesCore
|
||||||
|
- SDWebImage (~> 5.15.0)
|
||||||
|
- SDWebImageAVIFCoder (~> 0.9.4)
|
||||||
|
- SDWebImageSVGCoder (~> 1.6.1)
|
||||||
|
- SDWebImageWebPCoder (~> 0.9.1)
|
||||||
- ExpoKeepAwake (11.0.1):
|
- ExpoKeepAwake (11.0.1):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- ExpoLocalization (14.0.0):
|
- ExpoLocalization (14.1.0):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- ExpoModulesCore (1.1.1):
|
- ExpoModulesCore (1.1.1):
|
||||||
- React-Core
|
- React-Core
|
||||||
- ReactCommon/turbomodule/core
|
- ReactCommon/turbomodule/core
|
||||||
- ExpoRandom (13.0.0):
|
- ExpoRandom (13.1.0):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- ExpoStoreReview (6.1.0):
|
- ExpoStoreReview (6.2.0):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- ExpoVideoThumbnails (7.1.0):
|
- ExpoVideoThumbnails (7.2.0):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- ExpoWebBrowser (12.0.0):
|
- ExpoWebBrowser (12.0.0):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- EXScreenCapture (5.0.0):
|
- EXScreenCapture (5.1.0):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- EXScreenOrientation (5.0.1):
|
- EXScreenOrientation (5.1.0):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- React-Core
|
- React-Core
|
||||||
- EXSecureStore (12.0.0):
|
- EXSecureStore (12.1.0):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
- EXSplashScreen (0.17.5):
|
- EXSplashScreen (0.17.5):
|
||||||
- ExpoModulesCore
|
- ExpoModulesCore
|
||||||
|
@ -58,7 +64,16 @@ PODS:
|
||||||
- fmt (6.2.1)
|
- fmt (6.2.1)
|
||||||
- glog (0.3.5)
|
- glog (0.3.5)
|
||||||
- hermes-engine (0.70.7)
|
- hermes-engine (0.70.7)
|
||||||
|
- libaom (2.0.2):
|
||||||
|
- libvmaf
|
||||||
|
- libavif (0.10.1):
|
||||||
|
- libavif/libaom (= 0.10.1)
|
||||||
|
- libavif/core (0.10.1)
|
||||||
|
- libavif/libaom (0.10.1):
|
||||||
|
- libaom (>= 2.0.0)
|
||||||
|
- libavif/core
|
||||||
- libevent (2.1.12)
|
- libevent (2.1.12)
|
||||||
|
- libvmaf (2.2.0)
|
||||||
- libwebp (1.2.4):
|
- libwebp (1.2.4):
|
||||||
- libwebp/demux (= 1.2.4)
|
- libwebp/demux (= 1.2.4)
|
||||||
- libwebp/mux (= 1.2.4)
|
- libwebp/mux (= 1.2.4)
|
||||||
|
@ -299,8 +314,6 @@ PODS:
|
||||||
- glog
|
- glog
|
||||||
- react-native-blur (4.3.0):
|
- react-native-blur (4.3.0):
|
||||||
- React-Core
|
- React-Core
|
||||||
- react-native-blurhash (1.1.10):
|
|
||||||
- React-Core
|
|
||||||
- react-native-cameraroll (5.2.3):
|
- react-native-cameraroll (5.2.3):
|
||||||
- React-Core
|
- React-Core
|
||||||
- react-native-image-picker (5.0.1):
|
- react-native-image-picker (5.0.1):
|
||||||
|
@ -401,10 +414,6 @@ PODS:
|
||||||
- React-Core
|
- React-Core
|
||||||
- RNCClipboard (1.11.1):
|
- RNCClipboard (1.11.1):
|
||||||
- React-Core
|
- React-Core
|
||||||
- RNFastImage (8.6.3):
|
|
||||||
- React-Core
|
|
||||||
- SDWebImage (~> 5.15.0)
|
|
||||||
- SDWebImageWebPCoder (~> 0.9.1)
|
|
||||||
- RNGestureHandler (2.9.0):
|
- RNGestureHandler (2.9.0):
|
||||||
- React-Core
|
- React-Core
|
||||||
- RNReanimated (2.14.4):
|
- RNReanimated (2.14.4):
|
||||||
|
@ -447,6 +456,11 @@ PODS:
|
||||||
- SDWebImage (5.15.0):
|
- SDWebImage (5.15.0):
|
||||||
- SDWebImage/Core (= 5.15.0)
|
- SDWebImage/Core (= 5.15.0)
|
||||||
- SDWebImage/Core (5.15.0)
|
- SDWebImage/Core (5.15.0)
|
||||||
|
- SDWebImageAVIFCoder (0.9.5):
|
||||||
|
- libavif (>= 0.9.1)
|
||||||
|
- SDWebImage (~> 5.10)
|
||||||
|
- SDWebImageSVGCoder (1.6.1):
|
||||||
|
- SDWebImage/Core (~> 5.6)
|
||||||
- SDWebImageWebPCoder (0.9.1):
|
- SDWebImageWebPCoder (0.9.1):
|
||||||
- libwebp (~> 1.0)
|
- libwebp (~> 1.0)
|
||||||
- SDWebImage/Core (~> 5.13)
|
- SDWebImage/Core (~> 5.13)
|
||||||
|
@ -467,6 +481,7 @@ DEPENDENCIES:
|
||||||
- Expo (from `../node_modules/expo`)
|
- Expo (from `../node_modules/expo`)
|
||||||
- ExpoCrypto (from `../node_modules/expo-crypto/ios`)
|
- ExpoCrypto (from `../node_modules/expo-crypto/ios`)
|
||||||
- ExpoHaptics (from `../node_modules/expo-haptics/ios`)
|
- ExpoHaptics (from `../node_modules/expo-haptics/ios`)
|
||||||
|
- ExpoImage (from `../node_modules/expo-image/ios`)
|
||||||
- ExpoKeepAwake (from `../node_modules/expo-keep-awake/ios`)
|
- ExpoKeepAwake (from `../node_modules/expo-keep-awake/ios`)
|
||||||
- ExpoLocalization (from `../node_modules/expo-localization/ios`)
|
- ExpoLocalization (from `../node_modules/expo-localization/ios`)
|
||||||
- ExpoModulesCore (from `../node_modules/expo-modules-core`)
|
- ExpoModulesCore (from `../node_modules/expo-modules-core`)
|
||||||
|
@ -500,7 +515,6 @@ DEPENDENCIES:
|
||||||
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
|
- React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`)
|
||||||
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
|
- React-logger (from `../node_modules/react-native/ReactCommon/logger`)
|
||||||
- "react-native-blur (from `../node_modules/@react-native-community/blur`)"
|
- "react-native-blur (from `../node_modules/@react-native-community/blur`)"
|
||||||
- react-native-blurhash (from `../node_modules/react-native-blurhash`)
|
|
||||||
- "react-native-cameraroll (from `../node_modules/@react-native-camera-roll/camera-roll`)"
|
- "react-native-cameraroll (from `../node_modules/@react-native-camera-roll/camera-roll`)"
|
||||||
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
|
- react-native-image-picker (from `../node_modules/react-native-image-picker`)
|
||||||
- react-native-ios-context-menu (from `../node_modules/react-native-ios-context-menu`)
|
- react-native-ios-context-menu (from `../node_modules/react-native-ios-context-menu`)
|
||||||
|
@ -527,7 +541,6 @@ DEPENDENCIES:
|
||||||
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
|
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
|
||||||
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
|
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
|
||||||
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
|
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
|
||||||
- RNFastImage (from `../node_modules/react-native-fast-image`)
|
|
||||||
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
|
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
|
||||||
- RNReanimated (from `../node_modules/react-native-reanimated`)
|
- RNReanimated (from `../node_modules/react-native-reanimated`)
|
||||||
- RNScreens (from `../node_modules/react-native-screens`)
|
- RNScreens (from `../node_modules/react-native-screens`)
|
||||||
|
@ -539,11 +552,16 @@ DEPENDENCIES:
|
||||||
SPEC REPOS:
|
SPEC REPOS:
|
||||||
trunk:
|
trunk:
|
||||||
- fmt
|
- fmt
|
||||||
|
- libaom
|
||||||
|
- libavif
|
||||||
- libevent
|
- libevent
|
||||||
|
- libvmaf
|
||||||
- libwebp
|
- libwebp
|
||||||
- MMKV
|
- MMKV
|
||||||
- MMKVCore
|
- MMKVCore
|
||||||
- SDWebImage
|
- SDWebImage
|
||||||
|
- SDWebImageAVIFCoder
|
||||||
|
- SDWebImageSVGCoder
|
||||||
- SDWebImageWebPCoder
|
- SDWebImageWebPCoder
|
||||||
- Sentry
|
- Sentry
|
||||||
- Swime
|
- Swime
|
||||||
|
@ -573,6 +591,8 @@ EXTERNAL SOURCES:
|
||||||
:path: "../node_modules/expo-crypto/ios"
|
:path: "../node_modules/expo-crypto/ios"
|
||||||
ExpoHaptics:
|
ExpoHaptics:
|
||||||
:path: "../node_modules/expo-haptics/ios"
|
:path: "../node_modules/expo-haptics/ios"
|
||||||
|
ExpoImage:
|
||||||
|
:path: "../node_modules/expo-image/ios"
|
||||||
ExpoKeepAwake:
|
ExpoKeepAwake:
|
||||||
:path: "../node_modules/expo-keep-awake/ios"
|
:path: "../node_modules/expo-keep-awake/ios"
|
||||||
ExpoLocalization:
|
ExpoLocalization:
|
||||||
|
@ -635,8 +655,6 @@ EXTERNAL SOURCES:
|
||||||
:path: "../node_modules/react-native/ReactCommon/logger"
|
:path: "../node_modules/react-native/ReactCommon/logger"
|
||||||
react-native-blur:
|
react-native-blur:
|
||||||
:path: "../node_modules/@react-native-community/blur"
|
:path: "../node_modules/@react-native-community/blur"
|
||||||
react-native-blurhash:
|
|
||||||
:path: "../node_modules/react-native-blurhash"
|
|
||||||
react-native-cameraroll:
|
react-native-cameraroll:
|
||||||
:path: "../node_modules/@react-native-camera-roll/camera-roll"
|
:path: "../node_modules/@react-native-camera-roll/camera-roll"
|
||||||
react-native-image-picker:
|
react-native-image-picker:
|
||||||
|
@ -689,8 +707,6 @@ EXTERNAL SOURCES:
|
||||||
:path: "../node_modules/@react-native-async-storage/async-storage"
|
:path: "../node_modules/@react-native-async-storage/async-storage"
|
||||||
RNCClipboard:
|
RNCClipboard:
|
||||||
:path: "../node_modules/@react-native-clipboard/clipboard"
|
:path: "../node_modules/@react-native-clipboard/clipboard"
|
||||||
RNFastImage:
|
|
||||||
:path: "../node_modules/react-native-fast-image"
|
|
||||||
RNGestureHandler:
|
RNGestureHandler:
|
||||||
:path: "../node_modules/react-native-gesture-handler"
|
:path: "../node_modules/react-native-gesture-handler"
|
||||||
RNReanimated:
|
RNReanimated:
|
||||||
|
@ -710,32 +726,36 @@ SPEC CHECKSUMS:
|
||||||
boost: a7c83b31436843459a1961bfd74b96033dc77234
|
boost: a7c83b31436843459a1961bfd74b96033dc77234
|
||||||
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
|
DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54
|
||||||
EXApplication: 034b1c40a8e9fe1bff76a1e511ee90dff64ad834
|
EXApplication: 034b1c40a8e9fe1bff76a1e511ee90dff64ad834
|
||||||
EXAV: 4b92292fb107520a25956bea940a94a3bb4911ca
|
EXAV: 1242c4c206fc522058a2749019064e979a4c0b76
|
||||||
EXConstants: 44f7d347d0432a66f469d0ce1dc4e3a0ca1b8b2d
|
EXConstants: 397186c7e312c33eb1ab85fa1f434dc123778136
|
||||||
EXErrorRecovery: ae43433feb0608a64dc5b1c8363b3e7769a9ea24
|
EXErrorRecovery: ae43433feb0608a64dc5b1c8363b3e7769a9ea24
|
||||||
EXFileSystem: 60602b6eefa6873f97172c684b7537c9760b50d6
|
EXFileSystem: d9fea7fe7a4390a0ef226cac33958de9178388b9
|
||||||
EXFont: 319606bfe48c33b5b5063fb0994afdc496befe80
|
EXFont: 319606bfe48c33b5b5063fb0994afdc496befe80
|
||||||
EXNotifications: babce2a87b7922051354fcfe7a74dd279b7e272a
|
EXNotifications: babce2a87b7922051354fcfe7a74dd279b7e272a
|
||||||
Expo: b9fa98bf260992312ee3c424400819fb9beadafe
|
Expo: b9fa98bf260992312ee3c424400819fb9beadafe
|
||||||
ExpoCrypto: 6eb2a5ede7d95b7359a5f0391ee0c5d2ecd144b3
|
ExpoCrypto: 98c71864077c4d0fe798a6a5aee1a8c1294cef85
|
||||||
ExpoHaptics: 129d3f8d44c2205adcdf8db760602818463d5437
|
ExpoHaptics: 97c532f311c3e638c14a6134f23564d007b76de4
|
||||||
|
ExpoImage: 748f2b8d3974f1d51c7706fd61057b93241738aa
|
||||||
ExpoKeepAwake: 69b59d0a8d2b24de9f82759c39b3821fec030318
|
ExpoKeepAwake: 69b59d0a8d2b24de9f82759c39b3821fec030318
|
||||||
ExpoLocalization: e202d1e2a4950df17ac8d0889d65a1ffd7532d7e
|
ExpoLocalization: 28ce7cfa174a752f7ace84189710f1385373655b
|
||||||
ExpoModulesCore: 485dff3a59b036a33b6050c0a5aea3cf1037fdd1
|
ExpoModulesCore: 485dff3a59b036a33b6050c0a5aea3cf1037fdd1
|
||||||
ExpoRandom: 58b7e0a5fe1adf1cb6dc1cbe503a6fe9524f36ce
|
ExpoRandom: d8fc05d0d071485b06a97ab2a78cb7f8082052cd
|
||||||
ExpoStoreReview: 713336ff504db3a6983475bf7c67519cc5efc86f
|
ExpoStoreReview: e96ba0690ea21dc5d341cfafd0b26bac7bc974f5
|
||||||
ExpoVideoThumbnails: 424db02cedfbbe2d498bcb2712ea4ba8a9dcb453
|
ExpoVideoThumbnails: 865fa65f2b4f006ff02ef9e3e9c10370d9442d0a
|
||||||
ExpoWebBrowser: 073e50f16669d498fb49063b9b7fe780b24f7fda
|
ExpoWebBrowser: 073e50f16669d498fb49063b9b7fe780b24f7fda
|
||||||
EXScreenCapture: d9f1ec31042dfef109290d06c2b4789b7444d16d
|
EXScreenCapture: bcf94c8199cd1876166e384b2398ff519a8ef7ee
|
||||||
EXScreenOrientation: 07e5aeff07bce09a2b214981e612d87fd7719997
|
EXScreenOrientation: d43067a93e75234a7ce5154e2759fff2238dbfd5
|
||||||
EXSecureStore: daec0117c922a67c658cb229152a9e252e5c1750
|
EXSecureStore: ec150f49b22269022c6184f1711abb05fe98d72d
|
||||||
EXSplashScreen: 3e989924f61a8dd07ee4ea584c6ba14be9b51949
|
EXSplashScreen: 3e989924f61a8dd07ee4ea584c6ba14be9b51949
|
||||||
FBLazyVector: a6454570f573a0f6f1d397e5a95c13e8e45d1700
|
FBLazyVector: a6454570f573a0f6f1d397e5a95c13e8e45d1700
|
||||||
FBReactNativeSpec: 09e8dfba44487e5dc4882a9f5318cde67549549c
|
FBReactNativeSpec: 09e8dfba44487e5dc4882a9f5318cde67549549c
|
||||||
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
|
fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9
|
||||||
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
|
glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b
|
||||||
hermes-engine: 566e656aa95456a3f3f739fd76ea9a9656f2633f
|
hermes-engine: 566e656aa95456a3f3f739fd76ea9a9656f2633f
|
||||||
|
libaom: 9bb51e0f8f9192245e3ca2a1c9e4375d9cbccc52
|
||||||
|
libavif: e242998ccec1c83bcba0bbdc256f460ad5077348
|
||||||
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
|
libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913
|
||||||
|
libvmaf: 8d61aabc2f4ed3e6591cf7406fa00a223ec11289
|
||||||
libwebp: f62cb61d0a484ba548448a4bd52aabf150ff6eef
|
libwebp: f62cb61d0a484ba548448a4bd52aabf150ff6eef
|
||||||
MMKV: 7f34558bbb5a33b0eaefae2de4b6a20a2ffdad6f
|
MMKV: 7f34558bbb5a33b0eaefae2de4b6a20a2ffdad6f
|
||||||
MMKVCore: ddf41b9d9262f058419f9ba7598719af56c02cd3
|
MMKVCore: ddf41b9d9262f058419f9ba7598719af56c02cd3
|
||||||
|
@ -755,7 +775,6 @@ SPEC CHECKSUMS:
|
||||||
React-jsinspector: 1c34fea1868136ecde647bc11fae9266d4143693
|
React-jsinspector: 1c34fea1868136ecde647bc11fae9266d4143693
|
||||||
React-logger: e9f407f9fdf3f3ce7749ae6f88affe63e8446019
|
React-logger: e9f407f9fdf3f3ce7749ae6f88affe63e8446019
|
||||||
react-native-blur: 50c9feabacbc5f49b61337ebc32192c6be7ec3c3
|
react-native-blur: 50c9feabacbc5f49b61337ebc32192c6be7ec3c3
|
||||||
react-native-blurhash: add4df9a937b4e021a24bc67a0714f13e0bd40b7
|
|
||||||
react-native-cameraroll: 5b25d0be40185d02e522bf2abf8a1ba4e8faa107
|
react-native-cameraroll: 5b25d0be40185d02e522bf2abf8a1ba4e8faa107
|
||||||
react-native-image-picker: 8cb4280e2c1efc3daeb2d9d597f9429a60472e40
|
react-native-image-picker: 8cb4280e2c1efc3daeb2d9d597f9429a60472e40
|
||||||
react-native-ios-context-menu: e529171ba760a1af7f2ef0729f5a7f4d226171c5
|
react-native-ios-context-menu: e529171ba760a1af7f2ef0729f5a7f4d226171c5
|
||||||
|
@ -782,7 +801,6 @@ SPEC CHECKSUMS:
|
||||||
ReactCommon: 0253d197eaa7f6689dcd3e7d5360449ab93e10df
|
ReactCommon: 0253d197eaa7f6689dcd3e7d5360449ab93e10df
|
||||||
RNCAsyncStorage: 8616bd5a58af409453ea4e1b246521bb76578d60
|
RNCAsyncStorage: 8616bd5a58af409453ea4e1b246521bb76578d60
|
||||||
RNCClipboard: 2834e1c4af68697089cdd455ee4a4cdd198fa7dd
|
RNCClipboard: 2834e1c4af68697089cdd455ee4a4cdd198fa7dd
|
||||||
RNFastImage: bd611b5635f1e0f43c8ccf597b1ef6ee0d0f966d
|
|
||||||
RNGestureHandler: 071d7a9ad81e8b83fe7663b303d132406a7d8f39
|
RNGestureHandler: 071d7a9ad81e8b83fe7663b303d132406a7d8f39
|
||||||
RNReanimated: 6668b0587bebd4b15dd849b99e5a9c70fc12ed95
|
RNReanimated: 6668b0587bebd4b15dd849b99e5a9c70fc12ed95
|
||||||
RNScreens: ea4cd3a853063cda19a4e3c28d2e52180c80f4eb
|
RNScreens: ea4cd3a853063cda19a4e3c28d2e52180c80f4eb
|
||||||
|
@ -790,6 +808,8 @@ SPEC CHECKSUMS:
|
||||||
RNShareMenu: cb9dac548c8bf147d06f0bf07296ad51ea9f5fc3
|
RNShareMenu: cb9dac548c8bf147d06f0bf07296ad51ea9f5fc3
|
||||||
RNSVG: c1e76b81c76cdcd34b4e1188852892dc280eb902
|
RNSVG: c1e76b81c76cdcd34b4e1188852892dc280eb902
|
||||||
SDWebImage: 9bec4c5cdd9579e1f57104735ee0c37df274d593
|
SDWebImage: 9bec4c5cdd9579e1f57104735ee0c37df274d593
|
||||||
|
SDWebImageAVIFCoder: d759e21cf4efb640cc97250566aa556ad8bb877c
|
||||||
|
SDWebImageSVGCoder: 6fc109f9c2a82ab44510fff410b88b1a6c271ee8
|
||||||
SDWebImageWebPCoder: 18503de6621dd2c420d680e33d46bf8e1d5169b0
|
SDWebImageWebPCoder: 18503de6621dd2c420d680e33d46bf8e1d5169b0
|
||||||
Sentry: 4c9babff9034785067c896fd580b1f7de44da020
|
Sentry: 4c9babff9034785067c896fd580b1f7de44da020
|
||||||
Swime: d7b2c277503b6cea317774aedc2dce05613f8b0b
|
Swime: d7b2c277503b6cea317774aedc2dce05613f8b0b
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "tooot",
|
"name": "tooot",
|
||||||
"version": "4.8.7",
|
"version": "4.8.8",
|
||||||
"description": "tooot for Mastodon",
|
"description": "tooot for Mastodon",
|
||||||
"author": "xmflsct <me@xmflsct.com>",
|
"author": "xmflsct <me@xmflsct.com>",
|
||||||
"license": "GPL-3.0-or-later",
|
"license": "GPL-3.0-or-later",
|
||||||
|
@ -50,6 +50,7 @@
|
||||||
"expo-crypto": "^12.1.0",
|
"expo-crypto": "^12.1.0",
|
||||||
"expo-file-system": "^15.1.1",
|
"expo-file-system": "^15.1.1",
|
||||||
"expo-haptics": "^12.1.0",
|
"expo-haptics": "^12.1.0",
|
||||||
|
"expo-image": "^1.0.0-beta.6",
|
||||||
"expo-linking": "^3.3.0",
|
"expo-linking": "^3.3.0",
|
||||||
"expo-localization": "^14.0.0",
|
"expo-localization": "^14.0.0",
|
||||||
"expo-notifications": "^0.17.0",
|
"expo-notifications": "^0.17.0",
|
||||||
|
@ -70,14 +71,12 @@
|
||||||
"react-i18next": "^12.1.4",
|
"react-i18next": "^12.1.4",
|
||||||
"react-intl": "^6.2.7",
|
"react-intl": "^6.2.7",
|
||||||
"react-native": "^0.70.7",
|
"react-native": "^0.70.7",
|
||||||
"react-native-blurhash": "^1.1.10",
|
|
||||||
"react-native-fast-image": "^8.6.3",
|
|
||||||
"react-native-flash-message": "^0.4.0",
|
"react-native-flash-message": "^0.4.0",
|
||||||
"react-native-gesture-handler": "~2.9.0",
|
"react-native-gesture-handler": "~2.9.0",
|
||||||
"react-native-image-picker": "^5.0.1",
|
"react-native-image-picker": "^5.0.1",
|
||||||
"react-native-ios-context-menu": "^1.15.3",
|
"react-native-ios-context-menu": "^1.15.3",
|
||||||
"react-native-language-detection": "^0.2.2",
|
"react-native-language-detection": "^0.2.2",
|
||||||
"react-native-mmkv": "^2.5.1",
|
"react-native-mmkv": "~2.5.1",
|
||||||
"react-native-pager-view": "^6.1.2",
|
"react-native-pager-view": "^6.1.2",
|
||||||
"react-native-quick-base64": "^2.0.5",
|
"react-native-quick-base64": "^2.0.5",
|
||||||
"react-native-reanimated": "^2.14.4",
|
"react-native-reanimated": "^2.14.4",
|
||||||
|
@ -116,7 +115,6 @@
|
||||||
},
|
},
|
||||||
"packageManager": "yarn@3.3.1",
|
"packageManager": "yarn@3.3.1",
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"react-native-fast-image@^8.6.3": "patch:react-native-fast-image@npm%3A8.6.3#./.yarn/patches/react-native-fast-image-npm-8.6.3-03ee2d23c0.patch",
|
|
||||||
"expo-av@^13.0.2": "patch:expo-av@npm%3A13.0.2#./.yarn/patches/expo-av-npm-13.0.2-7a651776f1.patch",
|
"expo-av@^13.0.2": "patch:expo-av@npm%3A13.0.2#./.yarn/patches/expo-av-npm-13.0.2-7a651776f1.patch",
|
||||||
"react-native-share-menu@^6.0.0": "patch:react-native-share-menu@npm%3A6.0.0#./.yarn/patches/react-native-share-menu-npm-6.0.0-f1094c3204.patch",
|
"react-native-share-menu@^6.0.0": "patch:react-native-share-menu@npm%3A6.0.0#./.yarn/patches/react-native-share-menu-npm-6.0.0-f1094c3204.patch",
|
||||||
"@types/react-native-share-menu@^5.0.2": "patch:@types/react-native-share-menu@npm%3A5.0.2#./.yarn/patches/@types-react-native-share-menu-npm-5.0.2-373df17ecc.patch",
|
"@types/react-native-share-menu@^5.0.2": "patch:@types/react-native-share-menu@npm%3A5.0.2#./.yarn/patches/@types-react-native-share-menu-npm-5.0.2-373df17ecc.patch",
|
||||||
|
|
|
@ -11,6 +11,7 @@ import log from '@utils/startup/log'
|
||||||
import netInfo from '@utils/startup/netInfo'
|
import netInfo from '@utils/startup/netInfo'
|
||||||
import push from '@utils/startup/push'
|
import push from '@utils/startup/push'
|
||||||
import sentry from '@utils/startup/sentry'
|
import sentry from '@utils/startup/sentry'
|
||||||
|
import { GLOBAL } from '@utils/storage'
|
||||||
import { getGlobalStorage, setAccount, setGlobalStorage } from '@utils/storage/actions'
|
import { getGlobalStorage, setAccount, setGlobalStorage } from '@utils/storage/actions'
|
||||||
import { migrateFromAsyncStorage, versionStorageGlobal } from '@utils/storage/migrations/toMMKV'
|
import { migrateFromAsyncStorage, versionStorageGlobal } from '@utils/storage/migrations/toMMKV'
|
||||||
import ThemeManager from '@utils/styles/ThemeManager'
|
import ThemeManager from '@utils/styles/ThemeManager'
|
||||||
|
@ -24,10 +25,6 @@ import { enableFreeze } from 'react-native-screens'
|
||||||
import i18n from './i18n'
|
import i18n from './i18n'
|
||||||
import Screens from './screens'
|
import Screens from './screens'
|
||||||
|
|
||||||
export const GLOBAL: { connect?: boolean } = {
|
|
||||||
connect: undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
Platform.select({
|
Platform.select({
|
||||||
android: LogBox.ignoreLogs(['Setting a timer for a long period of time'])
|
android: LogBox.ignoreLogs(['Setting a timer for a long period of time'])
|
||||||
})
|
})
|
||||||
|
|
|
@ -38,7 +38,7 @@ const ComponentAccount: React.FC<PropsWithChildren & Props> = ({ account, props,
|
||||||
<>
|
<>
|
||||||
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center' }}>
|
<View style={{ flex: 1, flexDirection: 'row', alignItems: 'center' }}>
|
||||||
<GracefullyImage
|
<GracefullyImage
|
||||||
uri={{ original: account.avatar, static: account.avatar_static }}
|
sources={{ default: { uri: account.avatar }, static: { uri: account.avatar_static } }}
|
||||||
style={{
|
style={{
|
||||||
width: StyleConstants.Avatar.S,
|
width: StyleConstants.Avatar.S,
|
||||||
height: StyleConstants.Avatar.S,
|
height: StyleConstants.Avatar.S,
|
||||||
|
|
|
@ -40,7 +40,7 @@ const AccountButton: React.FC<Props> = ({ account, additionalActions }) => {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<GracefullyImage
|
<GracefullyImage
|
||||||
uri={{ original: account.avatar_static }}
|
sources={{ default: { uri: account.avatar_static } }}
|
||||||
dimension={{
|
dimension={{
|
||||||
width: StyleConstants.Font.Size.L,
|
width: StyleConstants.Font.Size.L,
|
||||||
height: StyleConstants.Font.Size.L
|
height: StyleConstants.Font.Size.L
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { getAccountStorage, setAccountStorage } from '@utils/storage/actions'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import layoutAnimation from '@utils/styles/layoutAnimation'
|
import layoutAnimation from '@utils/styles/layoutAnimation'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
|
import { Image } from 'expo-image'
|
||||||
import { chunk } from 'lodash'
|
import { chunk } from 'lodash'
|
||||||
import React, { useContext, useEffect, useRef, useState } from 'react'
|
import React, { useContext, useEffect, useRef, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
@ -19,7 +20,6 @@ import {
|
||||||
TextInput,
|
TextInput,
|
||||||
View
|
View
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import FastImage from 'react-native-fast-image'
|
|
||||||
import EmojisContext from './Context'
|
import EmojisContext from './Context'
|
||||||
|
|
||||||
const EmojisList = () => {
|
const EmojisList = () => {
|
||||||
|
@ -129,9 +129,7 @@ const EmojisList = () => {
|
||||||
}}
|
}}
|
||||||
style={{ padding: StyleConstants.Spacing.S }}
|
style={{ padding: StyleConstants.Spacing.S }}
|
||||||
>
|
>
|
||||||
<FastImage
|
<Image
|
||||||
enterTransition='fadeIn'
|
|
||||||
transitionDuration={60}
|
|
||||||
accessibilityLabel={t('common:customEmoji.accessibilityLabel', {
|
accessibilityLabel={t('common:customEmoji.accessibilityLabel', {
|
||||||
emoji: emoji.shortcode
|
emoji: emoji.shortcode
|
||||||
})}
|
})}
|
||||||
|
|
|
@ -1,36 +1,26 @@
|
||||||
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
|
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
|
||||||
import { connectMedia } from '@utils/api/helpers/connect'
|
import { connectMedia } from '@utils/api/helpers/connect'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { useEffect, useState } from 'react'
|
import { Image, ImageSource, ImageStyle } from 'expo-image'
|
||||||
import {
|
import React, { useState } from 'react'
|
||||||
AccessibilityProps,
|
import { AccessibilityProps, Pressable, StyleProp, View, ViewStyle } from 'react-native'
|
||||||
Image,
|
|
||||||
Pressable,
|
|
||||||
StyleProp,
|
|
||||||
StyleSheet,
|
|
||||||
View,
|
|
||||||
ViewStyle
|
|
||||||
} from 'react-native'
|
|
||||||
import { Blurhash } from 'react-native-blurhash'
|
|
||||||
import FastImage, { ImageStyle } from 'react-native-fast-image'
|
|
||||||
|
|
||||||
// blurhas -> if blurhash, show before any loading succeed
|
|
||||||
// original -> load original
|
|
||||||
// original, remote -> if original failed, then remote
|
|
||||||
// preview, original -> first show preview, then original
|
|
||||||
// preview, original, remote -> first show preview, then original, if original failed, then remote
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
accessibilityLabel?: AccessibilityProps['accessibilityLabel']
|
accessibilityLabel?: AccessibilityProps['accessibilityLabel']
|
||||||
accessibilityHint?: AccessibilityProps['accessibilityHint']
|
accessibilityHint?: AccessibilityProps['accessibilityHint']
|
||||||
|
|
||||||
hidden?: boolean
|
hidden?: boolean
|
||||||
uri: { preview?: string; original?: string; remote?: string; static?: string }
|
sources: {
|
||||||
blurhash?: string
|
preview?: ImageSource
|
||||||
|
default?: ImageSource
|
||||||
|
remote?: ImageSource
|
||||||
|
static?: ImageSource
|
||||||
|
blurhash?: string
|
||||||
|
}
|
||||||
dimension?: { width: number; height: number }
|
dimension?: { width: number; height: number }
|
||||||
onPress?: () => void
|
onPress?: () => void
|
||||||
style?: StyleProp<ViewStyle>
|
style?: StyleProp<ViewStyle>
|
||||||
imageStyle?: StyleProp<ImageStyle>
|
imageStyle?: ImageStyle
|
||||||
// For image viewer when there is no image size available
|
// For image viewer when there is no image size available
|
||||||
setImageDimensions?: React.Dispatch<
|
setImageDimensions?: React.Dispatch<
|
||||||
React.SetStateAction<{
|
React.SetStateAction<{
|
||||||
|
@ -39,49 +29,30 @@ export interface Props {
|
||||||
}>
|
}>
|
||||||
>
|
>
|
||||||
dim?: boolean
|
dim?: boolean
|
||||||
|
enableLiveTextInteraction?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const GracefullyImage = ({
|
const GracefullyImage = ({
|
||||||
accessibilityLabel,
|
accessibilityLabel,
|
||||||
accessibilityHint,
|
accessibilityHint,
|
||||||
hidden = false,
|
hidden = false,
|
||||||
uri,
|
sources,
|
||||||
blurhash,
|
|
||||||
dimension,
|
dimension,
|
||||||
onPress,
|
onPress,
|
||||||
style,
|
style,
|
||||||
imageStyle,
|
imageStyle,
|
||||||
setImageDimensions,
|
setImageDimensions,
|
||||||
dim
|
dim,
|
||||||
|
enableLiveTextInteraction = false
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const { reduceMotionEnabled } = useAccessibility()
|
const { reduceMotionEnabled } = useAccessibility()
|
||||||
const { colors, theme } = useTheme()
|
const { theme } = useTheme()
|
||||||
const [imageLoaded, setImageLoaded] = useState(false)
|
|
||||||
|
|
||||||
const [currentUri, setCurrentUri] = useState<string | undefined>(uri.original || uri.remote)
|
const [currentSource, setCurrentSource] = useState<ImageSource | undefined>(
|
||||||
const source: { uri?: string } = {
|
sources.default || sources.remote
|
||||||
uri: reduceMotionEnabled && uri.static ? uri.static : currentUri
|
)
|
||||||
}
|
const source: ImageSource | undefined =
|
||||||
useEffect(() => {
|
reduceMotionEnabled && sources.static ? sources.static : currentSource
|
||||||
if (
|
|
||||||
(uri.original ? currentUri !== uri.original : true) &&
|
|
||||||
(uri.remote ? currentUri !== uri.remote : true)
|
|
||||||
) {
|
|
||||||
setCurrentUri(uri.original || uri.remote)
|
|
||||||
}
|
|
||||||
}, [currentUri, uri.original, uri.remote])
|
|
||||||
|
|
||||||
const blurhashView = () => {
|
|
||||||
if (hidden || !imageLoaded) {
|
|
||||||
if (blurhash) {
|
|
||||||
return <Blurhash decodeAsync blurhash={blurhash} style={styles.placeholder} />
|
|
||||||
} else {
|
|
||||||
return <View style={[styles.placeholder, { backgroundColor: colors.shimmerDefault }]} />
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Pressable
|
<Pressable
|
||||||
|
@ -91,50 +62,41 @@ const GracefullyImage = ({
|
||||||
style={[style, dimension]}
|
style={[style, dimension]}
|
||||||
{...(onPress ? (hidden ? { disabled: true } : { onPress }) : { disabled: true })}
|
{...(onPress ? (hidden ? { disabled: true } : { onPress }) : { disabled: true })}
|
||||||
>
|
>
|
||||||
{uri.preview && !imageLoaded ? (
|
<Image
|
||||||
<FastImage
|
placeholderContentFit='cover'
|
||||||
source={connectMedia({ uri: uri.preview })}
|
placeholder={sources.blurhash || connectMedia(sources.preview)}
|
||||||
enterTransition='fadeIn'
|
source={hidden ? undefined : connectMedia(source)}
|
||||||
transitionDuration={60}
|
transition={{ duration: 80 }}
|
||||||
style={[styles.placeholder]}
|
style={{ flex: 1, ...imageStyle }}
|
||||||
/>
|
onLoad={event => {
|
||||||
) : null}
|
if (setImageDimensions && event.source) {
|
||||||
<FastImage
|
setImageDimensions(event.source)
|
||||||
source={connectMedia(source)}
|
|
||||||
enterTransition={!blurhash && !uri.preview ? 'fadeIn' : 'none'}
|
|
||||||
transitionDuration={60}
|
|
||||||
style={[{ flex: 1 }, imageStyle]}
|
|
||||||
onLoad={() => {
|
|
||||||
setImageLoaded(true)
|
|
||||||
if (setImageDimensions && source.uri) {
|
|
||||||
Image.getSize(source.uri, (width, height) => setImageDimensions({ width, height }))
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onError={() => {
|
onError={() => {
|
||||||
if (uri.original && uri.original === currentUri && uri.remote) {
|
if (
|
||||||
setCurrentUri(uri.remote)
|
sources.default?.uri &&
|
||||||
|
sources.default?.uri === currentSource?.uri &&
|
||||||
|
sources.remote
|
||||||
|
) {
|
||||||
|
setCurrentSource(sources.remote)
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
enableLiveTextInteraction={enableLiveTextInteraction}
|
||||||
/>
|
/>
|
||||||
{blurhashView()}
|
|
||||||
{dim && theme !== 'light' ? (
|
{dim && theme !== 'light' ? (
|
||||||
<View
|
<View
|
||||||
style={[
|
style={{
|
||||||
styles.placeholder,
|
width: '100%',
|
||||||
{ backgroundColor: 'black', opacity: theme === 'dark_lighter' ? 0.18 : 0.36 }
|
height: '100%',
|
||||||
]}
|
position: 'absolute',
|
||||||
|
backgroundColor: 'black',
|
||||||
|
opacity: theme === 'dark_lighter' ? 0.18 : 0.36
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</Pressable>
|
</Pressable>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
placeholder: {
|
|
||||||
width: '100%',
|
|
||||||
height: '100%',
|
|
||||||
position: 'absolute'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
export default GracefullyImage
|
export default GracefullyImage
|
||||||
|
|
|
@ -19,12 +19,13 @@ import {
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import * as AuthSession from 'expo-auth-session'
|
import * as AuthSession from 'expo-auth-session'
|
||||||
import * as Random from 'expo-random'
|
import * as Crypto from 'expo-crypto'
|
||||||
|
import { Image } from 'expo-image'
|
||||||
import * as WebBrowser from 'expo-web-browser'
|
import * as WebBrowser from 'expo-web-browser'
|
||||||
import { debounce } from 'lodash'
|
import { debounce } from 'lodash'
|
||||||
import React, { RefObject, useCallback, useState } from 'react'
|
import React, { RefObject, useCallback, useState } from 'react'
|
||||||
import { Trans, useTranslation } from 'react-i18next'
|
import { Trans, useTranslation } from 'react-i18next'
|
||||||
import { Alert, Image, KeyboardAvoidingView, Platform, TextInput, View } from 'react-native'
|
import { Alert, KeyboardAvoidingView, Platform, TextInput, View } from 'react-native'
|
||||||
import { ScrollView } from 'react-native-gesture-handler'
|
import { ScrollView } from 'react-native-gesture-handler'
|
||||||
import { fromByteArray } from 'react-native-quick-base64'
|
import { fromByteArray } from 'react-native-quick-base64'
|
||||||
import parse from 'url-parse'
|
import parse from 'url-parse'
|
||||||
|
@ -78,7 +79,8 @@ const ComponentInstance: React.FC<Props> = ({
|
||||||
clientId,
|
clientId,
|
||||||
clientSecret,
|
clientSecret,
|
||||||
scopes: variables.scopes,
|
scopes: variables.scopes,
|
||||||
redirectUri
|
redirectUri,
|
||||||
|
usePKCE: !['pawoo.net'].includes(domain)
|
||||||
})
|
})
|
||||||
await request.makeAuthUrlAsync(discovery)
|
await request.makeAuthUrlAsync(discovery)
|
||||||
|
|
||||||
|
@ -160,7 +162,7 @@ const ComponentInstance: React.FC<Props> = ({
|
||||||
'admin.sign_up': false,
|
'admin.sign_up': false,
|
||||||
'admin.report': false
|
'admin.report': false
|
||||||
},
|
},
|
||||||
key: fromByteArray(Random.getRandomBytes(16))
|
key: fromByteArray(Crypto.getRandomBytes(16))
|
||||||
},
|
},
|
||||||
page_local: {
|
page_local: {
|
||||||
showBoosts: true,
|
showBoosts: true,
|
||||||
|
@ -231,7 +233,7 @@ const ComponentInstance: React.FC<Props> = ({
|
||||||
<View style={{ flexDirection: 'row' }}>
|
<View style={{ flexDirection: 'row' }}>
|
||||||
<Image
|
<Image
|
||||||
source={require('assets/images/welcome.png')}
|
source={require('assets/images/welcome.png')}
|
||||||
style={{ resizeMode: 'contain', flex: 1, aspectRatio: 16 / 9 }}
|
style={{ flex: 1, aspectRatio: 16 / 9 }}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
) : null}
|
) : null}
|
||||||
|
|
|
@ -5,9 +5,9 @@ import { useGlobalStorage } from '@utils/storage/actions'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { adaptiveScale } from '@utils/styles/scaling'
|
import { adaptiveScale } from '@utils/styles/scaling'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
|
import { Image } from 'expo-image'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { ColorValue, Platform, TextStyle } from 'react-native'
|
import { ColorValue, Platform, TextStyle } from 'react-native'
|
||||||
import FastImage from 'react-native-fast-image'
|
|
||||||
|
|
||||||
const regexEmoji = new RegExp(/(:[A-Za-z0-9_]+:)/)
|
const regexEmoji = new RegExp(/(:[A-Za-z0-9_]+:)/)
|
||||||
|
|
||||||
|
@ -77,8 +77,8 @@ const ParseEmojis: React.FC<Props> = ({
|
||||||
return (
|
return (
|
||||||
<CustomText key={emojiShortcode + i}>
|
<CustomText key={emojiShortcode + i}>
|
||||||
{i === 0 ? ' ' : undefined}
|
{i === 0 ? ' ' : undefined}
|
||||||
<FastImage
|
<Image
|
||||||
source={connectMedia({ uri: uri.trim() })}
|
source={connectMedia({ uri })}
|
||||||
style={{
|
style={{
|
||||||
width: adaptedFontsize,
|
width: adaptedFontsize,
|
||||||
height: adaptedFontsize,
|
height: adaptedFontsize,
|
||||||
|
|
|
@ -79,7 +79,10 @@ const TimelineConversation: React.FC<Props> = ({ conversation, queryKey, highlig
|
||||||
{conversation.accounts.slice(0, 4).map(account => (
|
{conversation.accounts.slice(0, 4).map(account => (
|
||||||
<GracefullyImage
|
<GracefullyImage
|
||||||
key={account.id}
|
key={account.id}
|
||||||
uri={{ original: account.avatar, static: account.avatar_static }}
|
sources={{
|
||||||
|
default: { uri: account.avatar },
|
||||||
|
static: { uri: account.avatar_static }
|
||||||
|
}}
|
||||||
dimension={{
|
dimension={{
|
||||||
width: StyleConstants.Avatar.M,
|
width: StyleConstants.Avatar.M,
|
||||||
height:
|
height:
|
||||||
|
|
|
@ -12,11 +12,11 @@ import TimelinePoll from '@components/Timeline/Shared/Poll'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
import { StackNavigationProp } from '@react-navigation/stack'
|
import { StackNavigationProp } from '@react-navigation/stack'
|
||||||
import { featureCheck } from '@utils/helpers/featureCheck'
|
import { featureCheck } from '@utils/helpers/featureCheck'
|
||||||
|
import { checkIsMyAccount } from '@utils/helpers/isMyAccount'
|
||||||
import removeHTML from '@utils/helpers/removeHTML'
|
import removeHTML from '@utils/helpers/removeHTML'
|
||||||
import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
||||||
import { usePreferencesQuery } from '@utils/queryHooks/preferences'
|
import { usePreferencesQuery } from '@utils/queryHooks/preferences'
|
||||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||||
import { useAccountStorage } from '@utils/storage/actions'
|
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { Fragment, useRef, useState } from 'react'
|
import React, { Fragment, useRef, useState } from 'react'
|
||||||
|
@ -63,10 +63,9 @@ const TimelineDefault: React.FC<Props> = ({
|
||||||
const { colors } = useTheme()
|
const { colors } = useTheme()
|
||||||
const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>()
|
const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>()
|
||||||
|
|
||||||
const [accountId] = useAccountStorage.string('auth.account.id')
|
|
||||||
const { data: preferences } = usePreferencesQuery()
|
const { data: preferences } = usePreferencesQuery()
|
||||||
|
|
||||||
const ownAccount = status.account?.id === accountId
|
const isMyAccount = checkIsMyAccount(status.account.id)
|
||||||
const [spoilerExpanded, setSpoilerExpanded] = useState(
|
const [spoilerExpanded, setSpoilerExpanded] = useState(
|
||||||
preferences?.['reading:expand:spoilers'] || false
|
preferences?.['reading:expand:spoilers'] || false
|
||||||
)
|
)
|
||||||
|
@ -136,7 +135,7 @@ const TimelineDefault: React.FC<Props> = ({
|
||||||
const mStatus = menuStatus({ status, queryKey })
|
const mStatus = menuStatus({ status, queryKey })
|
||||||
const mInstance = menuInstance({ status, queryKey })
|
const mInstance = menuInstance({ status, queryKey })
|
||||||
|
|
||||||
if (!ownAccount) {
|
if (!isMyAccount) {
|
||||||
let filterResults: FilteredProps['filterResults'] = []
|
let filterResults: FilteredProps['filterResults'] = []
|
||||||
const [filterRevealed, setFilterRevealed] = useState(false)
|
const [filterRevealed, setFilterRevealed] = useState(false)
|
||||||
const hasFilterServerSide = featureCheck('filter_server_side')
|
const hasFilterServerSide = featureCheck('filter_server_side')
|
||||||
|
@ -166,7 +165,7 @@ const TimelineDefault: React.FC<Props> = ({
|
||||||
value={{
|
value={{
|
||||||
queryKey,
|
queryKey,
|
||||||
status,
|
status,
|
||||||
ownAccount,
|
isMyAccount,
|
||||||
spoilerHidden,
|
spoilerHidden,
|
||||||
rawContent,
|
rawContent,
|
||||||
detectedLanguage,
|
detectedLanguage,
|
||||||
|
|
|
@ -12,10 +12,10 @@ import TimelinePoll from '@components/Timeline/Shared/Poll'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
import { StackNavigationProp } from '@react-navigation/stack'
|
import { StackNavigationProp } from '@react-navigation/stack'
|
||||||
import { featureCheck } from '@utils/helpers/featureCheck'
|
import { featureCheck } from '@utils/helpers/featureCheck'
|
||||||
|
import { checkIsMyAccount } from '@utils/helpers/isMyAccount'
|
||||||
import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
||||||
import { usePreferencesQuery } from '@utils/queryHooks/preferences'
|
import { usePreferencesQuery } from '@utils/queryHooks/preferences'
|
||||||
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
import { QueryKeyTimeline } from '@utils/queryHooks/timeline'
|
||||||
import { useAccountStorage } from '@utils/storage/actions'
|
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React, { Fragment, useState } from 'react'
|
import React, { Fragment, useState } from 'react'
|
||||||
|
@ -32,7 +32,6 @@ export interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
const TimelineNotifications: React.FC<Props> = ({ notification, queryKey }) => {
|
const TimelineNotifications: React.FC<Props> = ({ notification, queryKey }) => {
|
||||||
const [accountId] = useAccountStorage.string('auth.account.id')
|
|
||||||
const { data: preferences } = usePreferencesQuery()
|
const { data: preferences } = usePreferencesQuery()
|
||||||
|
|
||||||
const status = notification.status?.reblog ? notification.status.reblog : notification.status
|
const status = notification.status?.reblog ? notification.status.reblog : notification.status
|
||||||
|
@ -42,7 +41,7 @@ const TimelineNotifications: React.FC<Props> = ({ notification, queryKey }) => {
|
||||||
: notification.status
|
: notification.status
|
||||||
? notification.status.account
|
? notification.status.account
|
||||||
: notification.account
|
: notification.account
|
||||||
const ownAccount = notification.account?.id === accountId
|
const isMyAccount = checkIsMyAccount(notification.account?.id)
|
||||||
const [spoilerExpanded, setSpoilerExpanded] = useState(
|
const [spoilerExpanded, setSpoilerExpanded] = useState(
|
||||||
preferences?.['reading:expand:spoilers'] || false
|
preferences?.['reading:expand:spoilers'] || false
|
||||||
)
|
)
|
||||||
|
@ -109,7 +108,7 @@ const TimelineNotifications: React.FC<Props> = ({ notification, queryKey }) => {
|
||||||
const mStatus = menuStatus({ status: notification.status, queryKey })
|
const mStatus = menuStatus({ status: notification.status, queryKey })
|
||||||
const mInstance = menuInstance({ status: notification.status, queryKey })
|
const mInstance = menuInstance({ status: notification.status, queryKey })
|
||||||
|
|
||||||
if (!ownAccount) {
|
if (!isMyAccount) {
|
||||||
let filterResults: FilteredProps['filterResults'] = []
|
let filterResults: FilteredProps['filterResults'] = []
|
||||||
const [filterRevealed, setFilterRevealed] = useState(false)
|
const [filterRevealed, setFilterRevealed] = useState(false)
|
||||||
const hasFilterServerSide = featureCheck('filter_server_side')
|
const hasFilterServerSide = featureCheck('filter_server_side')
|
||||||
|
@ -140,7 +139,7 @@ const TimelineNotifications: React.FC<Props> = ({ notification, queryKey }) => {
|
||||||
value={{
|
value={{
|
||||||
queryKey,
|
queryKey,
|
||||||
status,
|
status,
|
||||||
ownAccount,
|
isMyAccount,
|
||||||
spoilerHidden
|
spoilerHidden
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -22,7 +22,7 @@ import { Pressable, StyleSheet, View } from 'react-native'
|
||||||
import StatusContext from './Context'
|
import StatusContext from './Context'
|
||||||
|
|
||||||
const TimelineActions: React.FC = () => {
|
const TimelineActions: React.FC = () => {
|
||||||
const { queryKey, status, ownAccount, highlighted, disableDetails } = useContext(StatusContext)
|
const { queryKey, status, isMyAccount, highlighted, disableDetails } = useContext(StatusContext)
|
||||||
if (!queryKey || !status || disableDetails) return null
|
if (!queryKey || !status || disableDetails) return null
|
||||||
|
|
||||||
const navigationState = useNavState()
|
const navigationState = useNavState()
|
||||||
|
@ -182,7 +182,7 @@ const TimelineActions: React.FC = () => {
|
||||||
const childrenReblog = () => {
|
const childrenReblog = () => {
|
||||||
const color = (state: boolean) => (state ? colors.green : colors.secondary)
|
const color = (state: boolean) => (state ? colors.green : colors.secondary)
|
||||||
const disabled =
|
const disabled =
|
||||||
status.visibility === 'direct' || (status.visibility === 'private' && !ownAccount)
|
status.visibility === 'direct' || (status.visibility === 'private' && !isMyAccount)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Icon
|
<Icon
|
||||||
|
@ -196,7 +196,7 @@ const TimelineActions: React.FC = () => {
|
||||||
fontStyle='S'
|
fontStyle='S'
|
||||||
style={{
|
style={{
|
||||||
color:
|
color:
|
||||||
status.visibility === 'private' && !ownAccount
|
status.visibility === 'private' && !isMyAccount
|
||||||
? colors.disabled
|
? colors.disabled
|
||||||
: color(status.reblogged),
|
: color(status.reblogged),
|
||||||
marginLeft: StyleConstants.Spacing.XS
|
marginLeft: StyleConstants.Spacing.XS
|
||||||
|
@ -258,7 +258,7 @@ const TimelineActions: React.FC = () => {
|
||||||
onPress={onPressReblog}
|
onPress={onPressReblog}
|
||||||
children={childrenReblog()}
|
children={childrenReblog()}
|
||||||
disabled={
|
disabled={
|
||||||
status.visibility === 'direct' || (status.visibility === 'private' && !ownAccount)
|
status.visibility === 'direct' || (status.visibility === 'private' && !isMyAccount)
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ import { StackNavigationProp } from '@react-navigation/stack'
|
||||||
import { RootStackParamList } from '@utils/navigation/navigators'
|
import { RootStackParamList } from '@utils/navigation/navigators'
|
||||||
import { usePreferencesQuery } from '@utils/queryHooks/preferences'
|
import { usePreferencesQuery } from '@utils/queryHooks/preferences'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import layoutAnimation from '@utils/styles/layoutAnimation'
|
|
||||||
import React, { useContext, useState } from 'react'
|
import React, { useContext, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Pressable, View } from 'react-native'
|
import { Pressable, View } from 'react-native'
|
||||||
|
@ -207,7 +206,6 @@ const TimelineAttachment = () => {
|
||||||
content={t('shared.attachment.sensitive.button')}
|
content={t('shared.attachment.sensitive.button')}
|
||||||
overlay
|
overlay
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
layoutAnimation()
|
|
||||||
setSensitiveShown(false)
|
setSensitiveShown(false)
|
||||||
haptics('Light')
|
haptics('Light')
|
||||||
}}
|
}}
|
||||||
|
|
|
@ -7,7 +7,6 @@ import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import { Audio } from 'expo-av'
|
import { Audio } from 'expo-av'
|
||||||
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
import React, { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
import { AppState, AppStateStatus, StyleSheet, View } from 'react-native'
|
import { AppState, AppStateStatus, StyleSheet, View } from 'react-native'
|
||||||
import { Blurhash } from 'react-native-blurhash'
|
|
||||||
import AttachmentAltText from './AltText'
|
import AttachmentAltText from './AltText'
|
||||||
import { aspectRatio } from './dimensions'
|
import { aspectRatio } from './dimensions'
|
||||||
|
|
||||||
|
@ -72,19 +71,23 @@ const AttachmentAudio: React.FC<Props> = ({ total, index, sensitiveShown, audio
|
||||||
<View style={styles.overlay}>
|
<View style={styles.overlay}>
|
||||||
{sensitiveShown ? (
|
{sensitiveShown ? (
|
||||||
audio.blurhash ? (
|
audio.blurhash ? (
|
||||||
<Blurhash
|
<GracefullyImage
|
||||||
blurhash={audio.blurhash}
|
sources={{ blurhash: audio.blurhash }}
|
||||||
style={{
|
style={{
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%'
|
height: '100%'
|
||||||
}}
|
}}
|
||||||
|
dim
|
||||||
/>
|
/>
|
||||||
) : null
|
) : null
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
{audio.preview_url ? (
|
{audio.preview_url ? (
|
||||||
<GracefullyImage
|
<GracefullyImage
|
||||||
uri={{ original: audio.preview_url, remote: audio.preview_remote_url }}
|
sources={{
|
||||||
|
default: { uri: audio.preview_url },
|
||||||
|
remote: { uri: audio.preview_remote_url }
|
||||||
|
}}
|
||||||
style={styles.background}
|
style={styles.background}
|
||||||
dim
|
dim
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -35,8 +35,11 @@ const AttachmentImage = ({
|
||||||
<GracefullyImage
|
<GracefullyImage
|
||||||
accessibilityLabel={image.description}
|
accessibilityLabel={image.description}
|
||||||
hidden={sensitiveShown}
|
hidden={sensitiveShown}
|
||||||
uri={{ original: image.preview_url, remote: image.remote_url }}
|
sources={{
|
||||||
blurhash={image.blurhash}
|
default: { uri: image.preview_url },
|
||||||
|
remote: { uri: image.remote_url },
|
||||||
|
blurhash: image.blurhash
|
||||||
|
}}
|
||||||
onPress={() => navigateToImagesViewer(image.id)}
|
onPress={() => navigateToImagesViewer(image.id)}
|
||||||
style={{ aspectRatio: aspectRatio({ total, index, ...image.meta?.original }) }}
|
style={{ aspectRatio: aspectRatio({ total, index, ...image.meta?.original }) }}
|
||||||
dim
|
dim
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Button from '@components/Button'
|
import Button from '@components/Button'
|
||||||
|
import GracefullyImage from '@components/GracefullyImage'
|
||||||
import openLink from '@components/openLink'
|
import openLink from '@components/openLink'
|
||||||
import CustomText from '@components/Text'
|
import CustomText from '@components/Text'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
|
@ -6,7 +7,6 @@ import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { View } from 'react-native'
|
import { View } from 'react-native'
|
||||||
import { Blurhash } from 'react-native-blurhash'
|
|
||||||
import AttachmentAltText from './AltText'
|
import AttachmentAltText from './AltText'
|
||||||
import { aspectRatio } from './dimensions'
|
import { aspectRatio } from './dimensions'
|
||||||
|
|
||||||
|
@ -33,8 +33,8 @@ const AttachmentUnsupported: React.FC<Props> = ({ total, index, sensitiveShown,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{attachment.blurhash ? (
|
{attachment.blurhash ? (
|
||||||
<Blurhash
|
<GracefullyImage
|
||||||
blurhash={attachment.blurhash}
|
sources={{ blurhash: attachment.blurhash }}
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Button from '@components/Button'
|
import Button from '@components/Button'
|
||||||
|
import GracefullyImage from '@components/GracefullyImage'
|
||||||
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
|
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
|
||||||
import { connectMedia } from '@utils/api/helpers/connect'
|
import { connectMedia } from '@utils/api/helpers/connect'
|
||||||
import { useAccountStorage, useGlobalStorage } from '@utils/storage/actions'
|
import { useAccountStorage, useGlobalStorage } from '@utils/storage/actions'
|
||||||
|
@ -8,7 +9,6 @@ import { Platform } from 'expo-modules-core'
|
||||||
import * as ScreenOrientation from 'expo-screen-orientation'
|
import * as ScreenOrientation from 'expo-screen-orientation'
|
||||||
import React, { useRef, useState } from 'react'
|
import React, { useRef, useState } from 'react'
|
||||||
import { Pressable, View } from 'react-native'
|
import { Pressable, View } from 'react-native'
|
||||||
import { Blurhash } from 'react-native-blurhash'
|
|
||||||
import AttachmentAltText from './AltText'
|
import AttachmentAltText from './AltText'
|
||||||
import { aspectRatio } from './dimensions'
|
import { aspectRatio } from './dimensions'
|
||||||
|
|
||||||
|
@ -120,7 +120,10 @@ const AttachmentVideo: React.FC<Props> = ({
|
||||||
>
|
>
|
||||||
{sensitiveShown ? (
|
{sensitiveShown ? (
|
||||||
video.blurhash ? (
|
video.blurhash ? (
|
||||||
<Blurhash blurhash={video.blurhash} style={{ width: '100%', height: '100%' }} />
|
<GracefullyImage
|
||||||
|
sources={{ blurhash: video.blurhash }}
|
||||||
|
style={{ width: '100%', height: '100%' }}
|
||||||
|
/>
|
||||||
) : null
|
) : null
|
||||||
) : !gifv || (gifv && (reduceMotionEnabled || !shouldAutoplayGifv)) ? (
|
) : !gifv || (gifv && (reduceMotionEnabled || !shouldAutoplayGifv)) ? (
|
||||||
<Button
|
<Button
|
||||||
|
|
|
@ -33,7 +33,10 @@ const TimelineAvatar: React.FC<Props> = ({ account }) => {
|
||||||
onPress={() =>
|
onPress={() =>
|
||||||
!disableOnPress && navigation.push('Tab-Shared-Account', { account: actualAccount })
|
!disableOnPress && navigation.push('Tab-Shared-Account', { account: actualAccount })
|
||||||
}
|
}
|
||||||
uri={{ original: actualAccount.avatar, static: actualAccount.avatar_static }}
|
sources={{
|
||||||
|
default: { uri: actualAccount.avatar },
|
||||||
|
static: { uri: actualAccount.avatar_static }
|
||||||
|
}}
|
||||||
dimension={
|
dimension={
|
||||||
disableDetails || isConversation
|
disableDetails || isConversation
|
||||||
? {
|
? {
|
||||||
|
|
|
@ -82,8 +82,7 @@ const TimelineCard: React.FC = () => {
|
||||||
<>
|
<>
|
||||||
{status.card?.image ? (
|
{status.card?.image ? (
|
||||||
<GracefullyImage
|
<GracefullyImage
|
||||||
uri={{ original: status.card.image }}
|
sources={{ default: { uri: status.card.image }, blurhash: status.card.blurhash }}
|
||||||
blurhash={status.card.blurhash}
|
|
||||||
style={{ flexBasis: StyleConstants.Font.LineHeight.M * 5 }}
|
style={{ flexBasis: StyleConstants.Font.LineHeight.M * 5 }}
|
||||||
imageStyle={{ borderTopLeftRadius: 6, borderBottomLeftRadius: 6 }}
|
imageStyle={{ borderTopLeftRadius: 6, borderBottomLeftRadius: 6 }}
|
||||||
dim
|
dim
|
||||||
|
|
|
@ -8,7 +8,7 @@ type StatusContextType = {
|
||||||
|
|
||||||
status?: Mastodon.Status
|
status?: Mastodon.Status
|
||||||
|
|
||||||
ownAccount?: boolean
|
isMyAccount?: boolean
|
||||||
spoilerHidden?: boolean
|
spoilerHidden?: boolean
|
||||||
rawContent?: React.MutableRefObject<string[]> // When highlighted, for translate, edit history
|
rawContent?: React.MutableRefObject<string[]> // When highlighted, for translate, edit history
|
||||||
detectedLanguage?: React.MutableRefObject<string>
|
detectedLanguage?: React.MutableRefObject<string>
|
||||||
|
|
|
@ -21,7 +21,7 @@ import { Pressable, View } from 'react-native'
|
||||||
import StatusContext from './Context'
|
import StatusContext from './Context'
|
||||||
|
|
||||||
const TimelinePoll: React.FC = () => {
|
const TimelinePoll: React.FC = () => {
|
||||||
const { queryKey, status, ownAccount, spoilerHidden, disableDetails, highlighted } =
|
const { queryKey, status, isMyAccount, spoilerHidden, disableDetails, highlighted } =
|
||||||
useContext(StatusContext)
|
useContext(StatusContext)
|
||||||
if (!queryKey || !status || !status.poll) return null
|
if (!queryKey || !status || !status.poll) return null
|
||||||
const poll = status.poll
|
const poll = status.poll
|
||||||
|
@ -72,7 +72,7 @@ const TimelinePoll: React.FC = () => {
|
||||||
|
|
||||||
const pollButton = () => {
|
const pollButton = () => {
|
||||||
if (!poll.expired) {
|
if (!poll.expired) {
|
||||||
if (!ownAccount && !poll.voted) {
|
if (!isMyAccount && !poll.voted) {
|
||||||
return (
|
return (
|
||||||
<View style={{ marginRight: StyleConstants.Spacing.S }}>
|
<View style={{ marginRight: StyleConstants.Spacing.S }}>
|
||||||
<Button
|
<Button
|
||||||
|
|
|
@ -60,6 +60,9 @@ const Timeline: React.FC<Props> = ({
|
||||||
const { colors, theme } = useTheme()
|
const { colors, theme } = useTheme()
|
||||||
const { t } = useTranslation('componentTimeline')
|
const { t } = useTranslation('componentTimeline')
|
||||||
|
|
||||||
|
const firstLoad = useSharedValue<boolean>(!readMarker || disableRefresh)
|
||||||
|
const shouldAutoFetch = useSharedValue<boolean>(!!readMarker && !disableRefresh)
|
||||||
|
|
||||||
const { data, refetch, isFetching, isLoading, isRefetching, fetchNextPage, isFetchingNextPage } =
|
const { data, refetch, isFetching, isLoading, isRefetching, fetchNextPage, isFetchingNextPage } =
|
||||||
useTimelineQuery({
|
useTimelineQuery({
|
||||||
...queryKey[1],
|
...queryKey[1],
|
||||||
|
@ -68,7 +71,13 @@ const Timeline: React.FC<Props> = ({
|
||||||
notifyOnChangeProps: Platform.select({
|
notifyOnChangeProps: Platform.select({
|
||||||
ios: ['dataUpdatedAt', 'isFetching'],
|
ios: ['dataUpdatedAt', 'isFetching'],
|
||||||
android: ['dataUpdatedAt', 'isFetching', 'isLoading']
|
android: ['dataUpdatedAt', 'isFetching', 'isLoading']
|
||||||
})
|
}),
|
||||||
|
onSuccess: () => {
|
||||||
|
if (!firstLoad.value) {
|
||||||
|
firstLoad.value = true
|
||||||
|
fetchingType.value = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -90,6 +99,9 @@ const Timeline: React.FC<Props> = ({
|
||||||
(curr, prev) => {
|
(curr, prev) => {
|
||||||
if (curr !== null && prev === null) {
|
if (curr !== null && prev === null) {
|
||||||
notifiedFetchedNotice.value = false
|
notifiedFetchedNotice.value = false
|
||||||
|
if (curr === 0) {
|
||||||
|
shouldAutoFetch.value = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[fetchedCount]
|
[fetchedCount]
|
||||||
|
@ -129,19 +141,41 @@ const Timeline: React.FC<Props> = ({
|
||||||
fetchingType.value = 2
|
fetchingType.value = 2
|
||||||
} else if (y <= SEPARATION_Y_1) {
|
} else if (y <= SEPARATION_Y_1) {
|
||||||
fetchingType.value = 1
|
fetchingType.value = 1
|
||||||
|
shouldAutoFetch.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[isFetching]
|
[isFetching]
|
||||||
)
|
)
|
||||||
|
useAnimatedReaction(
|
||||||
|
() => scrollY.value < 600,
|
||||||
|
(curr, prev) => {
|
||||||
|
if (
|
||||||
|
curr === true &&
|
||||||
|
prev === false &&
|
||||||
|
!isFetchingPrev.value &&
|
||||||
|
fetchingType.value === 0 &&
|
||||||
|
shouldAutoFetch.value &&
|
||||||
|
Platform.OS === 'ios'
|
||||||
|
) {
|
||||||
|
fetchingType.value = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const latestMarker = useRef<string>()
|
const latestMarker = useRef<string>()
|
||||||
const updateMarkers = useCallback(
|
const updateMarkers = useCallback(
|
||||||
throttle(
|
throttle(() => {
|
||||||
() => readMarker && setAccountStorage([{ key: readMarker, value: latestMarker.current }]),
|
if (readMarker) {
|
||||||
1000 * 15
|
const currentMarker = getAccountStorage.string(readMarker) || '0'
|
||||||
),
|
if ((latestMarker.current || '0') > currentMarker) {
|
||||||
|
setAccountStorage([{ key: readMarker, value: latestMarker.current }])
|
||||||
|
} else {
|
||||||
|
// setAccountStorage([{ key: readMarker, value: '105250709762254246' }])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 1000 * 15),
|
||||||
[]
|
[]
|
||||||
)
|
)
|
||||||
readMarker &&
|
readMarker &&
|
||||||
|
@ -159,24 +193,14 @@ const Timeline: React.FC<Props> = ({
|
||||||
{
|
{
|
||||||
viewabilityConfig: {
|
viewabilityConfig: {
|
||||||
minimumViewTime: 300,
|
minimumViewTime: 300,
|
||||||
itemVisiblePercentThreshold: 80,
|
itemVisiblePercentThreshold: 10,
|
||||||
waitForInteraction: true
|
waitForInteraction: false
|
||||||
},
|
},
|
||||||
onViewableItemsChanged: ({ viewableItems }) => {
|
onViewableItemsChanged: ({ viewableItems }) => {
|
||||||
const marker = readMarker ? getAccountStorage.string(readMarker) : undefined
|
|
||||||
|
|
||||||
const firstItemId = viewableItems.filter(item => item.isViewable)[0]?.item.id
|
const firstItemId = viewableItems.filter(item => item.isViewable)[0]?.item.id
|
||||||
if (
|
if (!isFetchingPrev.value && !isRefetching && firstItemId) {
|
||||||
!isFetchingPrev.value &&
|
|
||||||
!isRefetching &&
|
|
||||||
firstItemId &&
|
|
||||||
firstItemId > (marker || '0')
|
|
||||||
) {
|
|
||||||
latestMarker.current = firstItemId
|
latestMarker.current = firstItemId
|
||||||
updateMarkers()
|
updateMarkers()
|
||||||
} else {
|
|
||||||
// latestMarker.current = '105250709762254246'
|
|
||||||
// updateMarkers()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { useNavigation } from '@react-navigation/native'
|
||||||
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||||
import { useQueryClient } from '@tanstack/react-query'
|
import { useQueryClient } from '@tanstack/react-query'
|
||||||
import apiInstance from '@utils/api/instance'
|
import apiInstance from '@utils/api/instance'
|
||||||
|
import { checkIsMyAccount } from '@utils/helpers/isMyAccount'
|
||||||
import { TabSharedStackParamList, useNavState } from '@utils/navigation/navigators'
|
import { TabSharedStackParamList, useNavState } from '@utils/navigation/navigators'
|
||||||
import { useAccountQuery } from '@utils/queryHooks/account'
|
import { useAccountQuery } from '@utils/queryHooks/account'
|
||||||
import {
|
import {
|
||||||
|
@ -15,7 +16,7 @@ import {
|
||||||
MutationVarsTimelineUpdateAccountProperty,
|
MutationVarsTimelineUpdateAccountProperty,
|
||||||
useTimelineMutation
|
useTimelineMutation
|
||||||
} from '@utils/queryHooks/timeline'
|
} from '@utils/queryHooks/timeline'
|
||||||
import { getAccountStorage, getReadableAccounts, useAccountStorage } from '@utils/storage/actions'
|
import { getAccountStorage, getReadableAccounts } from '@utils/storage/actions'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Alert, Platform } from 'react-native'
|
import { Alert, Platform } from 'react-native'
|
||||||
|
@ -40,19 +41,18 @@ const menuAccount = ({
|
||||||
|
|
||||||
const [enabled, setEnabled] = useState(openChange)
|
const [enabled, setEnabled] = useState(openChange)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!ownAccount && enabled === false && openChange === true) {
|
if (!isMyAccount && enabled === false && openChange === true) {
|
||||||
setEnabled(true)
|
setEnabled(true)
|
||||||
}
|
}
|
||||||
}, [openChange, enabled])
|
}, [openChange, enabled])
|
||||||
const { data: fetchedAccount } = useAccountQuery({ account, _local: true, options: { enabled } })
|
const { data: fetchedAccount } = useAccountQuery({ account, _local: true, options: { enabled } })
|
||||||
const actualAccount = status?._remote ? fetchedAccount : account
|
const actualAccount = status?._remote ? fetchedAccount : account
|
||||||
|
const isMyAccount = checkIsMyAccount(actualAccount?.id)
|
||||||
const { data, isFetched } = useRelationshipQuery({
|
const { data, isFetched } = useRelationshipQuery({
|
||||||
id: actualAccount?.id,
|
id: actualAccount?.id,
|
||||||
options: { enabled: !!actualAccount?.id && enabled }
|
options: { enabled: !!actualAccount?.id && enabled }
|
||||||
})
|
})
|
||||||
|
|
||||||
const ownAccount = useAccountStorage.string('auth.account.id')['0'] === actualAccount?.id
|
|
||||||
|
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const timelineMutation = useTimelineMutation({
|
const timelineMutation = useTimelineMutation({
|
||||||
onSuccess: (_, params) => {
|
onSuccess: (_, params) => {
|
||||||
|
@ -134,7 +134,7 @@ const menuAccount = ({
|
||||||
|
|
||||||
if (!account) return []
|
if (!account) return []
|
||||||
|
|
||||||
if (!ownAccount && Platform.OS !== 'android' && type !== 'account') {
|
if (!isMyAccount && Platform.OS !== 'android' && type !== 'account') {
|
||||||
menus[0].push({
|
menus[0].push({
|
||||||
type: 'item',
|
type: 'item',
|
||||||
key: 'account-following',
|
key: 'account-following',
|
||||||
|
@ -165,7 +165,7 @@ const menuAccount = ({
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ownAccount) {
|
if (!isMyAccount) {
|
||||||
menus[0].push({
|
menus[0].push({
|
||||||
type: 'item',
|
type: 'item',
|
||||||
key: 'account-list',
|
key: 'account-list',
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
||||||
import { useQueryClient } from '@tanstack/react-query'
|
import { useQueryClient } from '@tanstack/react-query'
|
||||||
import apiInstance from '@utils/api/instance'
|
import apiInstance from '@utils/api/instance'
|
||||||
import { featureCheck } from '@utils/helpers/featureCheck'
|
import { featureCheck } from '@utils/helpers/featureCheck'
|
||||||
|
import { checkIsMyAccount } from '@utils/helpers/isMyAccount'
|
||||||
import { RootStackParamList, useNavState } from '@utils/navigation/navigators'
|
import { RootStackParamList, useNavState } from '@utils/navigation/navigators'
|
||||||
import {
|
import {
|
||||||
MutationVarsTimelineUpdateStatusProperty,
|
MutationVarsTimelineUpdateStatusProperty,
|
||||||
|
@ -57,9 +58,8 @@ const menuStatus = ({
|
||||||
|
|
||||||
const menus: ContextMenu = []
|
const menus: ContextMenu = []
|
||||||
|
|
||||||
const [accountId] = useAccountStorage.string('auth.account.id')
|
|
||||||
const [accountAcct] = useAccountStorage.string('auth.account.acct')
|
const [accountAcct] = useAccountStorage.string('auth.account.acct')
|
||||||
const ownAccount = accountId === status.account?.id
|
const isMyAccount = checkIsMyAccount(status.account.id)
|
||||||
|
|
||||||
const canEditPost = featureCheck('edit_post')
|
const canEditPost = featureCheck('edit_post')
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ const menuStatus = ({
|
||||||
},
|
},
|
||||||
disabled: false,
|
disabled: false,
|
||||||
destructive: false,
|
destructive: false,
|
||||||
hidden: !ownAccount || !canEditPost
|
hidden: !isMyAccount || !canEditPost
|
||||||
},
|
},
|
||||||
title: t('componentContextMenu:status.edit.action'),
|
title: t('componentContextMenu:status.edit.action'),
|
||||||
icon: 'square.and.pencil'
|
icon: 'square.and.pencil'
|
||||||
|
@ -142,7 +142,7 @@ const menuStatus = ({
|
||||||
),
|
),
|
||||||
disabled: false,
|
disabled: false,
|
||||||
destructive: true,
|
destructive: true,
|
||||||
hidden: !ownAccount
|
hidden: !isMyAccount
|
||||||
},
|
},
|
||||||
title: t('componentContextMenu:status.deleteEdit.action'),
|
title: t('componentContextMenu:status.deleteEdit.action'),
|
||||||
icon: 'pencil.and.outline'
|
icon: 'pencil.and.outline'
|
||||||
|
@ -171,7 +171,7 @@ const menuStatus = ({
|
||||||
),
|
),
|
||||||
disabled: false,
|
disabled: false,
|
||||||
destructive: true,
|
destructive: true,
|
||||||
hidden: !ownAccount
|
hidden: !isMyAccount
|
||||||
},
|
},
|
||||||
title: t('componentContextMenu:status.delete.action'),
|
title: t('componentContextMenu:status.delete.action'),
|
||||||
icon: 'trash'
|
icon: 'trash'
|
||||||
|
@ -195,7 +195,7 @@ const menuStatus = ({
|
||||||
disabled: false,
|
disabled: false,
|
||||||
destructive: false,
|
destructive: false,
|
||||||
hidden:
|
hidden:
|
||||||
!ownAccount &&
|
!isMyAccount &&
|
||||||
queryKey[1].page !== 'Notifications' &&
|
queryKey[1].page !== 'Notifications' &&
|
||||||
!status.mentions?.find(
|
!status.mentions?.find(
|
||||||
mention => mention.acct === accountAcct && mention.username === accountAcct
|
mention => mention.acct === accountAcct && mention.username === accountAcct
|
||||||
|
@ -224,7 +224,7 @@ const menuStatus = ({
|
||||||
}),
|
}),
|
||||||
disabled: status.visibility !== 'public' && status.visibility !== 'unlisted',
|
disabled: status.visibility !== 'public' && status.visibility !== 'unlisted',
|
||||||
destructive: false,
|
destructive: false,
|
||||||
hidden: !ownAccount
|
hidden: !isMyAccount
|
||||||
},
|
},
|
||||||
title: t('componentContextMenu:status.pin.action', {
|
title: t('componentContextMenu:status.pin.action', {
|
||||||
defaultValue: 'false',
|
defaultValue: 'false',
|
||||||
|
@ -236,8 +236,9 @@ const menuStatus = ({
|
||||||
type: 'item',
|
type: 'item',
|
||||||
key: 'status-filter',
|
key: 'status-filter',
|
||||||
props: {
|
props: {
|
||||||
// @ts-ignore
|
onSelect: () =>
|
||||||
onSelect: () => navigation.navigate('Tab-Shared-Filter', { source: 'status', status, queryKey }),
|
// @ts-ignore
|
||||||
|
navigation.navigate('Tab-Shared-Filter', { source: 'status', status, queryKey }),
|
||||||
disabled: false,
|
disabled: false,
|
||||||
destructive: false,
|
destructive: false,
|
||||||
hidden: !('filtered' in status)
|
hidden: !('filtered' in status)
|
||||||
|
|
|
@ -46,17 +46,9 @@ const openLink = async (url: string, navigation?: any) => {
|
||||||
|
|
||||||
// If an account can be found
|
// If an account can be found
|
||||||
if (match?.account) {
|
if (match?.account) {
|
||||||
if (!match.account._remote && match.account.id) {
|
|
||||||
handleNavigation('Tab-Shared-Account', { account: match.account.id })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let response: Mastodon.Account | undefined = undefined
|
let response: Mastodon.Account | undefined = undefined
|
||||||
|
|
||||||
const queryKey: QueryKeyAccount = [
|
const queryKey: QueryKeyAccount = ['Account', { url: url, _remote: match.account._remote }]
|
||||||
'Account',
|
|
||||||
{ id: match.account.id, url: url, _remote: match.account._remote }
|
|
||||||
]
|
|
||||||
const cache = queryClient.getQueryData<Mastodon.Status>(queryKey)
|
const cache = queryClient.getQueryData<Mastodon.Status>(queryKey)
|
||||||
|
|
||||||
if (cache) {
|
if (cache) {
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
"poll": "S'ha acabat una enquesta en què havies participat",
|
"poll": "S'ha acabat una enquesta en què havies participat",
|
||||||
"reblog": {
|
"reblog": {
|
||||||
"default": "{{name}} ha impulsat",
|
"default": "{{name}} ha impulsat",
|
||||||
"myself": "",
|
"myself": "He impulsat",
|
||||||
"notification": "{{name}} ha impulsat la teva publicació"
|
"notification": "{{name}} ha impulsat la teva publicació"
|
||||||
},
|
},
|
||||||
"update": "L'impuls ha sigut editat",
|
"update": "L'impuls ha sigut editat",
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
"poll": "Eine Umfrage, an der du teilgenommen hast, ist beendet",
|
"poll": "Eine Umfrage, an der du teilgenommen hast, ist beendet",
|
||||||
"reblog": {
|
"reblog": {
|
||||||
"default": "{{name}} hat geboostet",
|
"default": "{{name}} hat geboostet",
|
||||||
"myself": "",
|
"myself": "Von mir geboosted",
|
||||||
"notification": "{{name}} hat deinen Tröt geboostet"
|
"notification": "{{name}} hat deinen Tröt geboostet"
|
||||||
},
|
},
|
||||||
"update": "Boost wurde bearbeitet",
|
"update": "Boost wurde bearbeitet",
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
"poll": "Una encuesta en la que has votado ha terminado",
|
"poll": "Una encuesta en la que has votado ha terminado",
|
||||||
"reblog": {
|
"reblog": {
|
||||||
"default": "{{name}} ha impulsado",
|
"default": "{{name}} ha impulsado",
|
||||||
"myself": "",
|
"myself": "He impulsado",
|
||||||
"notification": "{{name}} ha impulsado tu toot"
|
"notification": "{{name}} ha impulsado tu toot"
|
||||||
},
|
},
|
||||||
"update": "El impulso ha sido editado",
|
"update": "El impulso ha sido editado",
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
"poll": "Erantzun zenuen inkesta bat amaitu da",
|
"poll": "Erantzun zenuen inkesta bat amaitu da",
|
||||||
"reblog": {
|
"reblog": {
|
||||||
"default": "{{name}}-(e)k bultzatu du",
|
"default": "{{name}}-(e)k bultzatu du",
|
||||||
"myself": "",
|
"myself": "Bultzatu dut",
|
||||||
"notification": "{{name}}-(e)k zure tuta bultzatu du"
|
"notification": "{{name}}-(e)k zure tuta bultzatu du"
|
||||||
},
|
},
|
||||||
"update": "Bultzada editatua izan da",
|
"update": "Bultzada editatua izan da",
|
||||||
|
|
|
@ -19,8 +19,8 @@
|
||||||
"refetch": "更新",
|
"refetch": "更新",
|
||||||
"fetching": "新しいトゥートを取得しています...",
|
"fetching": "新しいトゥートを取得しています...",
|
||||||
"fetched": {
|
"fetched": {
|
||||||
"none": "",
|
"none": "新しいトゥートはありません",
|
||||||
"found": ""
|
"found": "{{count}}トゥートを取得"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shared": {
|
"shared": {
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
"poll": "アンケートが終了しました",
|
"poll": "アンケートが終了しました",
|
||||||
"reblog": {
|
"reblog": {
|
||||||
"default": "{{name}}さんがブースト",
|
"default": "{{name}}さんがブースト",
|
||||||
"myself": "",
|
"myself": "ブーストしました",
|
||||||
"notification": "{{name}}さんがあなたのトゥートをブーストしました"
|
"notification": "{{name}}さんがあなたのトゥートをブーストしました"
|
||||||
},
|
},
|
||||||
"update": "ブーストしたトゥートが編集されました",
|
"update": "ブーストしたトゥートが編集されました",
|
||||||
|
|
|
@ -73,13 +73,13 @@
|
||||||
"name": "設定"
|
"name": "設定"
|
||||||
},
|
},
|
||||||
"preferencesFilters": {
|
"preferencesFilters": {
|
||||||
"name": ""
|
"name": "すべてのコンテンツフィルター"
|
||||||
},
|
},
|
||||||
"preferencesFilterAdd": {
|
"preferencesFilterAdd": {
|
||||||
"name": "フィルターを作成"
|
"name": "フィルターを作成"
|
||||||
},
|
},
|
||||||
"preferencesFilterEdit": {
|
"preferencesFilterEdit": {
|
||||||
"name": ""
|
"name": "フィルターを編集"
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
"name": "プロフィールを編集"
|
"name": "プロフィールを編集"
|
||||||
|
@ -136,7 +136,7 @@
|
||||||
},
|
},
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"visibility": {
|
"visibility": {
|
||||||
"title": "",
|
"title": "デフォルトの投稿の表示",
|
||||||
"options": {
|
"options": {
|
||||||
"public": "公開",
|
"public": "公開",
|
||||||
"unlisted": "未収載",
|
"unlisted": "未収載",
|
||||||
|
@ -144,40 +144,40 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sensitive": {
|
"sensitive": {
|
||||||
"title": ""
|
"title": "メディアを常に閲覧注意としてマークする"
|
||||||
},
|
},
|
||||||
"media": {
|
"media": {
|
||||||
"title": "",
|
"title": "メディアの表示",
|
||||||
"options": {
|
"options": {
|
||||||
"default": "",
|
"default": "閲覧注意としてマークされたメディアを隠す",
|
||||||
"show_all": "",
|
"show_all": "メディアを常に表示する",
|
||||||
"hide_all": ""
|
"hide_all": "メディアを常に隠す"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"spoilers": {
|
"spoilers": {
|
||||||
"title": ""
|
"title": "閲覧注意としてマークされたトゥートを常に展開する"
|
||||||
},
|
},
|
||||||
"autoplay_gifs": {
|
"autoplay_gifs": {
|
||||||
"title": ""
|
"title": "トゥートでGIFを自動再生"
|
||||||
},
|
},
|
||||||
"filters": {
|
"filters": {
|
||||||
"title": "",
|
"title": "コンテンツフィルター",
|
||||||
"content": ""
|
"content": "{{count}} がアクティブです"
|
||||||
},
|
},
|
||||||
"web_only": {
|
"web_only": {
|
||||||
"title": "",
|
"title": "アップデート設定",
|
||||||
"description": ""
|
"description": "以下の設定は、web UI を使用してのみ更新できます"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"preferencesFilters": {
|
"preferencesFilters": {
|
||||||
"expired": "期限切れ",
|
"expired": "期限切れ",
|
||||||
"keywords_one": "",
|
"keywords_one": "{{count}}件のキーワード",
|
||||||
"keywords_other": "",
|
"keywords_other": "{{count}}件のキーワード",
|
||||||
"statuses_one": "",
|
"statuses_one": "{{count}}トゥート",
|
||||||
"statuses_other": "",
|
"statuses_other": "{{count}}トゥート",
|
||||||
"context": "",
|
"context": "<0 />で適用",
|
||||||
"contexts": {
|
"contexts": {
|
||||||
"home": "",
|
"home": "フォロー中とリスト",
|
||||||
"notifications": "通知",
|
"notifications": "通知",
|
||||||
"public": "連合",
|
"public": "連合",
|
||||||
"thread": "会話",
|
"thread": "会話",
|
||||||
|
@ -196,22 +196,22 @@
|
||||||
"604800": "1週間後",
|
"604800": "1週間後",
|
||||||
"18144000": "1ヶ月後"
|
"18144000": "1ヶ月後"
|
||||||
},
|
},
|
||||||
"context": "",
|
"context": "適用:",
|
||||||
"contexts": {
|
"contexts": {
|
||||||
"home": "",
|
"home": "フォロー中とリスト",
|
||||||
"notifications": "通知",
|
"notifications": "通知",
|
||||||
"public": "連合タイムライン",
|
"public": "連合タイムライン",
|
||||||
"thread": "",
|
"thread": "会話表示",
|
||||||
"account": ""
|
"account": "プロフィール表示"
|
||||||
},
|
},
|
||||||
"action": "",
|
"action": "一致した時",
|
||||||
"actions": {
|
"actions": {
|
||||||
"warn": "",
|
"warn": "",
|
||||||
"hide": ""
|
"hide": "完全に非表示にする"
|
||||||
},
|
},
|
||||||
"keywords": "",
|
"keywords": "これらのキーワードと一致",
|
||||||
"keyword": "キーワード",
|
"keyword": "キーワード",
|
||||||
"statuses": ""
|
"statuses": "これらのトゥートと一致"
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
"feedback": {
|
"feedback": {
|
||||||
|
@ -401,7 +401,7 @@
|
||||||
},
|
},
|
||||||
"filter": {
|
"filter": {
|
||||||
"name": "フィルターに追加",
|
"name": "フィルターに追加",
|
||||||
"existed": ""
|
"existed": "フィルター内に存在"
|
||||||
},
|
},
|
||||||
"history": {
|
"history": {
|
||||||
"name": "編集履歴"
|
"name": "編集履歴"
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
"action_false": "사용자 팔로우",
|
"action_false": "사용자 팔로우",
|
||||||
"action_true": "사용자 팔로우 해제"
|
"action_true": "사용자 팔로우 해제"
|
||||||
},
|
},
|
||||||
"inLists": "",
|
"inLists": "사용자를 포함한 리스트 ...",
|
||||||
"showBoosts": {
|
"showBoosts": {
|
||||||
"action_false": "사용자의 부스트 보이기",
|
"action_false": "사용자의 부스트 보이기",
|
||||||
"action_true": "사용자의 부스트 숨기기"
|
"action_true": "사용자의 부스트 숨기기"
|
||||||
|
@ -16,12 +16,12 @@
|
||||||
"action_true": "사용자 뮤트 해제"
|
"action_true": "사용자 뮤트 해제"
|
||||||
},
|
},
|
||||||
"followAs": {
|
"followAs": {
|
||||||
"trigger": "",
|
"trigger": "특정 계정에서 팔로우 ...",
|
||||||
"succeed_default": "@{{source}} 계정에서 @{{target}} 계정을 팔로우 했어요.",
|
"succeed_default": "@{{source}} 계정에서 @{{target}} 계정을 팔로우 했어요.",
|
||||||
"succeed_locked": "@{{source}} 계정에서 @{{target}} 계정의 팔로우 승인을 요청했어요.",
|
"succeed_locked": "@{{source}} 계정에서 @{{target}} 계정의 팔로우 승인을 요청했어요.",
|
||||||
"failed": "특정 계정에서 팔로우"
|
"failed": "특정 계정에서 팔로우"
|
||||||
},
|
},
|
||||||
"blockReport": "",
|
"blockReport": "차단 및 신고",
|
||||||
"block": {
|
"block": {
|
||||||
"action_false": "사용자 차단",
|
"action_false": "사용자 차단",
|
||||||
"action_true": "사용자 차단 해제",
|
"action_true": "사용자 차단 해제",
|
||||||
|
@ -56,11 +56,11 @@
|
||||||
},
|
},
|
||||||
"hashtag": {
|
"hashtag": {
|
||||||
"follow": {
|
"follow": {
|
||||||
"action_false": "",
|
"action_false": "팔로우",
|
||||||
"action_true": ""
|
"action_true": "팔로우 해제"
|
||||||
},
|
},
|
||||||
"filter": {
|
"filter": {
|
||||||
"action": ""
|
"action": "해시태그 필터 ..."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"share": {
|
"share": {
|
||||||
|
@ -99,8 +99,8 @@
|
||||||
"action_true": "툿 고정 해제"
|
"action_true": "툿 고정 해제"
|
||||||
},
|
},
|
||||||
"filter": {
|
"filter": {
|
||||||
"action_false": "",
|
"action_false": "툿 필터 ...",
|
||||||
"action_true": ""
|
"action_true": "필터 관리 ..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,10 +17,10 @@
|
||||||
"refresh": {
|
"refresh": {
|
||||||
"fetchPreviousPage": "이 시점에 이어서 불러오기",
|
"fetchPreviousPage": "이 시점에 이어서 불러오기",
|
||||||
"refetch": "최신 내용 불러오기",
|
"refetch": "최신 내용 불러오기",
|
||||||
"fetching": "",
|
"fetching": "새로운 툿 불러오는 중 ...",
|
||||||
"fetched": {
|
"fetched": {
|
||||||
"none": "",
|
"none": "새로운 툿이 없어요",
|
||||||
"found": ""
|
"found": "새로운 툿 {{count}}개를 불러왔어요"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shared": {
|
"shared": {
|
||||||
|
@ -33,7 +33,7 @@
|
||||||
"poll": "내가 참여한 투표가 끝났어요",
|
"poll": "내가 참여한 투표가 끝났어요",
|
||||||
"reblog": {
|
"reblog": {
|
||||||
"default": "{{name}} 님이 부스트했어요",
|
"default": "{{name}} 님이 부스트했어요",
|
||||||
"myself": "",
|
"myself": "내가 부스트함",
|
||||||
"notification": "{{name}} 님이 내 툿을 부스트했어요"
|
"notification": "{{name}} 님이 내 툿을 부스트했어요"
|
||||||
},
|
},
|
||||||
"update": "부스트한 툿이 수정됨",
|
"update": "부스트한 툿이 수정됨",
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"title": "작성을 취소할까요?",
|
"title": "작성을 취소할까요?",
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"save": "임시 저장",
|
"save": "임시 저장",
|
||||||
"delete": "임시 저장한 내용 삭제"
|
"delete": "작성중인 내용 삭제"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -70,16 +70,16 @@
|
||||||
"name": "푸시 알림"
|
"name": "푸시 알림"
|
||||||
},
|
},
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"name": ""
|
"name": "설정"
|
||||||
},
|
},
|
||||||
"preferencesFilters": {
|
"preferencesFilters": {
|
||||||
"name": ""
|
"name": "콘텐츠 필터"
|
||||||
},
|
},
|
||||||
"preferencesFilterAdd": {
|
"preferencesFilterAdd": {
|
||||||
"name": ""
|
"name": "필터 만들기"
|
||||||
},
|
},
|
||||||
"preferencesFilterEdit": {
|
"preferencesFilterEdit": {
|
||||||
"name": ""
|
"name": "필터 편집"
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
"name": "프로필 편집"
|
"name": "프로필 편집"
|
||||||
|
@ -136,81 +136,81 @@
|
||||||
},
|
},
|
||||||
"preferences": {
|
"preferences": {
|
||||||
"visibility": {
|
"visibility": {
|
||||||
"title": "",
|
"title": "공개 범위 기본값",
|
||||||
"options": {
|
"options": {
|
||||||
"public": "",
|
"public": "공개",
|
||||||
"unlisted": "",
|
"unlisted": "공개 타임라인에 비표시",
|
||||||
"private": ""
|
"private": "팔로워만"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sensitive": {
|
"sensitive": {
|
||||||
"title": ""
|
"title": "민감한 미디어 표시를 기본값으로 사용"
|
||||||
},
|
},
|
||||||
"media": {
|
"media": {
|
||||||
"title": "",
|
"title": "미디어 표시",
|
||||||
"options": {
|
"options": {
|
||||||
"default": "",
|
"default": "민감한 미디어 숨기기",
|
||||||
"show_all": "",
|
"show_all": "모든 미디어 표시",
|
||||||
"hide_all": ""
|
"hide_all": "모든 미디어 숨기기"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"spoilers": {
|
"spoilers": {
|
||||||
"title": ""
|
"title": "스포일러 경고가 있는 툿 자동으로 펼치기"
|
||||||
},
|
},
|
||||||
"autoplay_gifs": {
|
"autoplay_gifs": {
|
||||||
"title": ""
|
"title": "툿에 포함된 GIF 자동 재생"
|
||||||
},
|
},
|
||||||
"filters": {
|
"filters": {
|
||||||
"title": "",
|
"title": "콘텐츠 필터",
|
||||||
"content": ""
|
"content": "{{count}}개 활성화"
|
||||||
},
|
},
|
||||||
"web_only": {
|
"web_only": {
|
||||||
"title": "",
|
"title": "추가 설정",
|
||||||
"description": ""
|
"description": "일부 설정은 웹 UI에서만 변경할 수 있어요"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"preferencesFilters": {
|
"preferencesFilters": {
|
||||||
"expired": "",
|
"expired": "만료됨",
|
||||||
"keywords_one": "",
|
"keywords_one": "{{count}}개의 단어",
|
||||||
"keywords_other": "",
|
"keywords_other": "{{count}}개의 단어",
|
||||||
"statuses_one": "",
|
"statuses_one": "{{count}}개의 툿",
|
||||||
"statuses_other": "",
|
"statuses_other": "{{count}}개의 툿",
|
||||||
"context": "",
|
"context": "<0 />에 적용됨",
|
||||||
"contexts": {
|
"contexts": {
|
||||||
"home": "",
|
"home": "팔로우와 리스트",
|
||||||
"notifications": "",
|
"notifications": "알림",
|
||||||
"public": "",
|
"public": "연합",
|
||||||
"thread": "",
|
"thread": "대화",
|
||||||
"account": ""
|
"account": "프로필"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"preferencesFilter": {
|
"preferencesFilter": {
|
||||||
"name": "",
|
"name": "이름",
|
||||||
"expiration": "",
|
"expiration": "만료일",
|
||||||
"expirationOptions": {
|
"expirationOptions": {
|
||||||
"0": "",
|
"0": "만료하지 않음",
|
||||||
"1800": "",
|
"1800": "30분 후",
|
||||||
"3600": "",
|
"3600": "1시간 후",
|
||||||
"43200": "",
|
"43200": "12시간 후",
|
||||||
"86400": "",
|
"86400": "1일 후",
|
||||||
"604800": "",
|
"604800": "1주일 후",
|
||||||
"18144000": ""
|
"18144000": "1개월 후"
|
||||||
},
|
},
|
||||||
"context": "",
|
"context": "적용할 대상",
|
||||||
"contexts": {
|
"contexts": {
|
||||||
"home": "",
|
"home": "팔로우와 리스트",
|
||||||
"notifications": "",
|
"notifications": "알림",
|
||||||
"public": "",
|
"public": "연합 타임라인",
|
||||||
"thread": "",
|
"thread": "대화 내용",
|
||||||
"account": ""
|
"account": "프로필 내용"
|
||||||
},
|
},
|
||||||
"action": "",
|
"action": "필터 동작",
|
||||||
"actions": {
|
"actions": {
|
||||||
"warn": "",
|
"warn": "내용만 가리고 펼쳐볼 수 있게 하기",
|
||||||
"hide": ""
|
"hide": "완전히 숨기기"
|
||||||
},
|
},
|
||||||
"keywords": "",
|
"keywords": "필터할 단어",
|
||||||
"keyword": "",
|
"keyword": "단어",
|
||||||
"statuses": ""
|
"statuses": ""
|
||||||
},
|
},
|
||||||
"profile": {
|
"profile": {
|
||||||
|
@ -400,7 +400,7 @@
|
||||||
"name": "<0 /><1>의 미디어</1>"
|
"name": "<0 /><1>의 미디어</1>"
|
||||||
},
|
},
|
||||||
"filter": {
|
"filter": {
|
||||||
"name": "",
|
"name": "필터에 추가",
|
||||||
"existed": ""
|
"existed": ""
|
||||||
},
|
},
|
||||||
"history": {
|
"history": {
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"buttons": {
|
||||||
|
"OK": "OK",
|
||||||
|
"apply": "Bruk",
|
||||||
|
"cancel": "Avbryt",
|
||||||
|
"discard": "Forkast",
|
||||||
|
"continue": "Fortsett",
|
||||||
|
"create": "Opprett",
|
||||||
|
"delete": "Slett",
|
||||||
|
"done": "Fullført",
|
||||||
|
"confirm": "Bekreft"
|
||||||
|
},
|
||||||
|
"customEmoji": {
|
||||||
|
"accessibilityLabel": "Tilpasset emoji {{emoji}}"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"success": {
|
||||||
|
"message": "{{function}} var vellykket"
|
||||||
|
},
|
||||||
|
"warning": {
|
||||||
|
"message": ""
|
||||||
|
},
|
||||||
|
"error": {
|
||||||
|
"message": "{{function}} feilet, vennligst prøv igjen"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"separator": ", ",
|
||||||
|
"discard": {
|
||||||
|
"title": "Endringene er ikke lagret",
|
||||||
|
"message": "Dine endringer er ikke lagret. Angrer du på endringene?"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
{
|
||||||
|
"accessibilityHint": "Handlinger for tut, for eksempel dens bruker, tut selv",
|
||||||
|
"account": {
|
||||||
|
"title": "Brukerhandlinger",
|
||||||
|
"following": {
|
||||||
|
"action_false": "Følg bruker",
|
||||||
|
"action_true": "Slutt å følge"
|
||||||
|
},
|
||||||
|
"inLists": "Lister som inneholder bruker ...",
|
||||||
|
"showBoosts": {
|
||||||
|
"action_false": "Vis brukerens booster",
|
||||||
|
"action_true": "Skjul brukernes booster"
|
||||||
|
},
|
||||||
|
"mute": {
|
||||||
|
"action_false": "Demp bruker",
|
||||||
|
"action_true": "Opphev demping av bruker"
|
||||||
|
},
|
||||||
|
"followAs": {
|
||||||
|
"trigger": "Følg som ...",
|
||||||
|
"succeed_default": "Følger nå @{{target}} med @{{source}}",
|
||||||
|
"succeed_locked": "Sendt følge forespørsel til @{{target}} med {{source}}, venter på godkjenning",
|
||||||
|
"failed": "Følg som"
|
||||||
|
},
|
||||||
|
"blockReport": "Blokker og rapporter",
|
||||||
|
"block": {
|
||||||
|
"action_false": "Blokker bruker",
|
||||||
|
"action_true": "Fjern blokkering av brukker",
|
||||||
|
"alert": {
|
||||||
|
"title": "Bekreft blokkering av @{{username}}?"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"reports": {
|
||||||
|
"action": "Rapporter og blokker bruker",
|
||||||
|
"alert": {
|
||||||
|
"title": "Bekreft blokkering av @{{username}}?"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"at": {
|
||||||
|
"direct": "Direktemelding",
|
||||||
|
"public": "Offentlig melding"
|
||||||
|
},
|
||||||
|
"copy": {
|
||||||
|
"action": "Kopier tut",
|
||||||
|
"succeed": "Kopiert"
|
||||||
|
},
|
||||||
|
"instance": {
|
||||||
|
"title": "Instansaktivitet",
|
||||||
|
"block": {
|
||||||
|
"action": "Blokker instans {{instance}}",
|
||||||
|
"alert": {
|
||||||
|
"title": "Bekreft blokkering av @{{instance}}?",
|
||||||
|
"message": "For det meste kan du dempe eller blokkere visse brukere.\n\nEtter at du har blokkert, vil alt innholdet fra denne forekomsten bli fjernet!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hashtag": {
|
||||||
|
"follow": {
|
||||||
|
"action_false": "Følg",
|
||||||
|
"action_true": "Slutt å følge"
|
||||||
|
},
|
||||||
|
"filter": {
|
||||||
|
"action": "Filtrer emnet ..."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"share": {
|
||||||
|
"status": {
|
||||||
|
"action": "Del tut"
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"action": "Del bruker"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"title": "Tut handlinger",
|
||||||
|
"edit": {
|
||||||
|
"action": "Rediger tut"
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"action": "Slett tut",
|
||||||
|
"alert": {
|
||||||
|
"title": "Bekreft sletting?",
|
||||||
|
"message": "Alle booster og favoritter blir slettet, inkludert alle svar."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"deleteEdit": {
|
||||||
|
"action": "Slett tut og repost",
|
||||||
|
"alert": {
|
||||||
|
"title": "Bekreft sletting og repost?",
|
||||||
|
"message": "Alle booster og favoritter blir slettet, inkludert alle svar."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mute": {
|
||||||
|
"action_false": "Demp tut og svar",
|
||||||
|
"action_true": "Avdemp tut og svar"
|
||||||
|
},
|
||||||
|
"pin": {
|
||||||
|
"action_false": "Fest tut",
|
||||||
|
"action_true": "Avfest tut"
|
||||||
|
},
|
||||||
|
"filter": {
|
||||||
|
"action_false": "Filtrer tut...",
|
||||||
|
"action_true": "Behandle filtere..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"frequentUsed": "Ofte brukt"
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
{
|
||||||
|
"server": {
|
||||||
|
"textInput": {
|
||||||
|
"placeholder": "Instansens domene"
|
||||||
|
},
|
||||||
|
"whitelisted": "Dette kan være en hvitelistet forekomst som tooot ikke kan hente data fra før du logger inn.",
|
||||||
|
"button": "Logg inn",
|
||||||
|
"information": {
|
||||||
|
"name": "Navn",
|
||||||
|
"accounts": "Brukere",
|
||||||
|
"statuses": "Tuter",
|
||||||
|
"domains": "Universum"
|
||||||
|
},
|
||||||
|
"disclaimer": {
|
||||||
|
"base": "Innlogging bruker systemnettleser mens du logger inn på, din kontoinformasjon vil ikke være synlig for toot-appen."
|
||||||
|
},
|
||||||
|
"terms": {
|
||||||
|
"base": "Ved å logge inn godtar du <0>retningslinjer for personvern</0> og <1>vilkårene for bruk</1>."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"update": {
|
||||||
|
"alert": {
|
||||||
|
"title": "Logget på denne instansen",
|
||||||
|
"message": "Du kan logge inn på en annen konto, og beholde eksisterende pålogging"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"title": "Velg mediekilde",
|
||||||
|
"message": "Media EXIF-data er ikke lastet opp",
|
||||||
|
"options": {
|
||||||
|
"image": "Last opp bilder",
|
||||||
|
"image_max": "Last opp bilder (maks {{max}})",
|
||||||
|
"video": "Last opp video",
|
||||||
|
"video_max": "Last opp video (maks {{max}})"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"HTML": {
|
||||||
|
"accessibilityHint": "Trykk for å utvide eller skjule innhold",
|
||||||
|
"expanded": "{{hint}}{{moreLines}}",
|
||||||
|
"moreLines": " ({{count}} flere linjer)",
|
||||||
|
"defaultHint": "Lang tut"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"follow": {
|
||||||
|
"function": "Følg bruker"
|
||||||
|
},
|
||||||
|
"block": {
|
||||||
|
"function": "Blokker bruker"
|
||||||
|
},
|
||||||
|
"button": {
|
||||||
|
"error": "Feil med lasting",
|
||||||
|
"blocked_by": "Blokkert av bruker",
|
||||||
|
"blocking": "Fjern blokkering",
|
||||||
|
"following": "Slutt å følge",
|
||||||
|
"requested": "Avbryt forespørsel",
|
||||||
|
"default": "Følg"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
{
|
||||||
|
"empty": {
|
||||||
|
"error": {
|
||||||
|
"message": "Lasting mislyktes",
|
||||||
|
"button": "Prøv igjen"
|
||||||
|
},
|
||||||
|
"success": {
|
||||||
|
"message": "Tidslinjen er tom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"end": {
|
||||||
|
"message": "Slutt, hva med en kopp med <0 />"
|
||||||
|
},
|
||||||
|
"lookback": {
|
||||||
|
"message": "Sist lest"
|
||||||
|
},
|
||||||
|
"refresh": {
|
||||||
|
"fetchPreviousPage": "Nyere herfra",
|
||||||
|
"refetch": "Til nyeste",
|
||||||
|
"fetching": "Henter nyere tuter ...",
|
||||||
|
"fetched": {
|
||||||
|
"none": "Ingen nyere tut",
|
||||||
|
"found": "Hentet {{count}} tuter"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"shared": {
|
||||||
|
"actioned": {
|
||||||
|
"pinned": "Festet",
|
||||||
|
"favourite": "{{name}} favoriserte din tut",
|
||||||
|
"status": "{name} la nettopp ut",
|
||||||
|
"follow": "{{name}} følger deg",
|
||||||
|
"follow_request": "{{name}} ba om å følge deg",
|
||||||
|
"poll": "En avstemming du har stemt på er avsluttet",
|
||||||
|
"reblog": {
|
||||||
|
"default": "{{name}} boostet",
|
||||||
|
"myself": "Jeg boostet",
|
||||||
|
"notification": "{{name}} boostet ditt tut"
|
||||||
|
},
|
||||||
|
"update": "Reblogg har blitt redigert",
|
||||||
|
"admin.sign_up": "{{name}} ble med i instansen",
|
||||||
|
"admin.report": "{{name}} rapportert:"
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"reply": {
|
||||||
|
"accessibilityLabel": "Svar på tut"
|
||||||
|
},
|
||||||
|
"reblogged": {
|
||||||
|
"accessibilityLabel": "Boost denne tut",
|
||||||
|
"function": "Boost tut",
|
||||||
|
"options": {
|
||||||
|
"title": "Velg synlighet for boost",
|
||||||
|
"public": "Offentlig boost",
|
||||||
|
"unlisted": "Fjern boost"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"favourited": {
|
||||||
|
"accessibilityLabel": "Legge tut til dine favoritter",
|
||||||
|
"function": "Favoritt tut"
|
||||||
|
},
|
||||||
|
"bookmarked": {
|
||||||
|
"accessibilityLabel": "Legg tut til bokmerker",
|
||||||
|
"function": "Bokmerk tut"
|
||||||
|
},
|
||||||
|
"openReport": "Åpne rapport"
|
||||||
|
},
|
||||||
|
"actionsUsers": {
|
||||||
|
"reblogged_by": {
|
||||||
|
"accessibilityLabel": "{{count}} brukere har boostet tuten",
|
||||||
|
"accessibilityHint": "Trykk for å bli kjent med brukerne",
|
||||||
|
"text": "$t(screenTabs:shared.users.statuses.reblogged_by)"
|
||||||
|
},
|
||||||
|
"favourited_by": {
|
||||||
|
"accessibilityLabel": "{{count}} brukere har boostet tuten",
|
||||||
|
"accessibilityHint": "Trykk for å bli kjent med brukerne",
|
||||||
|
"text": "$t(screenTabs:shared.users.statuses.favourited_by)"
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
"accessibilityLabel": "Tut har blitt redigert {{count}} ganger",
|
||||||
|
"accessibilityHint": "Trykk for å vise hele redigeringsloggen",
|
||||||
|
"text_one": "{{count}} rediger",
|
||||||
|
"text_other": "{{count}} redigeringer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"attachment": {
|
||||||
|
"sensitive": {
|
||||||
|
"button": "Vis sensitivt media"
|
||||||
|
},
|
||||||
|
"unsupported": {
|
||||||
|
"text": "Feil med lasting",
|
||||||
|
"button": "Prøv ekstern lenke"
|
||||||
|
},
|
||||||
|
"altText": "Alternativ tekst"
|
||||||
|
},
|
||||||
|
"avatar": {
|
||||||
|
"accessibilityLabel": "Profilbilde av {{name}}",
|
||||||
|
"accessibilityHint": "Trykk for å gå til {{name}} sin side"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"expandHint": "Skjult innhold"
|
||||||
|
},
|
||||||
|
"filtered": {
|
||||||
|
"reveal": "Vis likevel",
|
||||||
|
"match_v1": "Filtrert: {{phrase}}.",
|
||||||
|
"match_v2_one": "Filtrert av {{filters}}.",
|
||||||
|
"match_v2_other": "Filtrert med {{count}} filtre, {{filters}}."
|
||||||
|
},
|
||||||
|
"fullConversation": "Vis samtaler",
|
||||||
|
"translate": {
|
||||||
|
"default": "Oversett",
|
||||||
|
"succeed": "Oversatt med {{provider}} fra {{source}}",
|
||||||
|
"failed": "Oversettelse feilet",
|
||||||
|
"source_not_supported": "dette språket er ikke støttet",
|
||||||
|
"target_not_supported": "Dette språket er ikke støttet"
|
||||||
|
},
|
||||||
|
"header": {
|
||||||
|
"shared": {
|
||||||
|
"account": {
|
||||||
|
"name": {
|
||||||
|
"accessibilityHint": "Brukerens visningsnavn"
|
||||||
|
},
|
||||||
|
"account": {
|
||||||
|
"accessibilityHint": "Brukerkonto"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"application": "med {{application}}",
|
||||||
|
"edited": {
|
||||||
|
"accessibilityLabel": "Tut redigert"
|
||||||
|
},
|
||||||
|
"muted": {
|
||||||
|
"accessibilityLabel": "Tut er dempet"
|
||||||
|
},
|
||||||
|
"replies": "Svar <0 />",
|
||||||
|
"visibility": {
|
||||||
|
"direct": {
|
||||||
|
"accessibilityLabel": "Tut er en direkte melding"
|
||||||
|
},
|
||||||
|
"private": {
|
||||||
|
"accessibilityLabel": "Tut er kun synlig for følgere"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"conversation": {
|
||||||
|
"withAccounts": "Med",
|
||||||
|
"delete": {
|
||||||
|
"function": "Slett direkte melding"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"poll": {
|
||||||
|
"meta": {
|
||||||
|
"button": {
|
||||||
|
"vote": "Stem",
|
||||||
|
"refresh": "Oppdater"
|
||||||
|
},
|
||||||
|
"count": {
|
||||||
|
"voters_one": "{{count}} bruker har stemt",
|
||||||
|
"voters_other": "{{count}} bruker har stemt",
|
||||||
|
"votes_one": "%{count} stemme",
|
||||||
|
"votes_other": "%{count} stemmer"
|
||||||
|
},
|
||||||
|
"expiration": {
|
||||||
|
"expired": "Avstemning utløpt",
|
||||||
|
"until": "Utløper <0 />"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"screenshot": {
|
||||||
|
"title": "Personvernbeskyttelse",
|
||||||
|
"message": "Vennligst ikke avslør brukerens identitet, som f. eks. brukernavn, profilbilde, osv. Tusen takk!"
|
||||||
|
},
|
||||||
|
"localCorrupt": {
|
||||||
|
"message": "Din økt er utløpt, vennligst logg inn igjen"
|
||||||
|
},
|
||||||
|
"pushError": {
|
||||||
|
"message": "Feil ved push-tjeneste",
|
||||||
|
"description": "Vennligst aktiver push-varsling i innstillingene"
|
||||||
|
},
|
||||||
|
"shareError": {
|
||||||
|
"imageNotSupported": "Bildetype {{type}} støttes ikke",
|
||||||
|
"videoNotSupported": "Videotype {{type}} støttes ikke"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"heading": "Del tut...",
|
||||||
|
"content": {
|
||||||
|
"select_account": "Velg konto"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"heading": "Kunngjøringer",
|
||||||
|
"content": {
|
||||||
|
"published": "Publisert <0 />",
|
||||||
|
"button": {
|
||||||
|
"read": "Les",
|
||||||
|
"unread": "Merk som lest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,171 @@
|
||||||
|
{
|
||||||
|
"heading": {
|
||||||
|
"left": {
|
||||||
|
"alert": {
|
||||||
|
"title": "Avbryte redigering?",
|
||||||
|
"buttons": {
|
||||||
|
"save": "Lagre utkast",
|
||||||
|
"delete": "Slett utkast"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"right": {
|
||||||
|
"button": {
|
||||||
|
"default": "Tut",
|
||||||
|
"conversation": "Tut DM",
|
||||||
|
"reply": "Tut svar",
|
||||||
|
"deleteEdit": "Tut",
|
||||||
|
"edit": "Tut",
|
||||||
|
"share": "Tut"
|
||||||
|
},
|
||||||
|
"alert": {
|
||||||
|
"default": {
|
||||||
|
"title": "Tut mislyktes",
|
||||||
|
"button": "Prøv igjen"
|
||||||
|
},
|
||||||
|
"removeReply": {
|
||||||
|
"title": "Svar på tut ble ikke funnet",
|
||||||
|
"description": "Svarte tut kan ha blitt slettet. Vil du fjerne det fra din referanse?",
|
||||||
|
"confirm": "Fjern referanse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"root": {
|
||||||
|
"header": {
|
||||||
|
"postingAs": "Tuter som @{{acct}}@{{domain}}",
|
||||||
|
"spoilerInput": {
|
||||||
|
"placeholder": "Spoiler advarsel"
|
||||||
|
},
|
||||||
|
"textInput": {
|
||||||
|
"placeholder": "Hva tenker du på",
|
||||||
|
"keyboardImage": {
|
||||||
|
"exceedMaximum": {
|
||||||
|
"title": "Maksimalt antall vedlegg nådd"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"footer": {
|
||||||
|
"attachments": {
|
||||||
|
"sensitive": "Merk vedlegg som følsomt",
|
||||||
|
"remove": {
|
||||||
|
"accessibilityLabel": "Fjern opplastet vedlegg, nummer {{attachment}}"
|
||||||
|
},
|
||||||
|
"edit": {
|
||||||
|
"accessibilityLabel": "Rediger opplastet vedlegg, nummer {{attachment}}"
|
||||||
|
},
|
||||||
|
"upload": {
|
||||||
|
"accessibilityLabel": "Last opp flere vedlegg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"emojis": {
|
||||||
|
"accessibilityHint": "Trykk for å legge til emoji"
|
||||||
|
},
|
||||||
|
"poll": {
|
||||||
|
"option": {
|
||||||
|
"placeholder": {
|
||||||
|
"accessibilityLabel": "Avstemningsvalg {{index}}",
|
||||||
|
"single": "Ett valg",
|
||||||
|
"multiple": "Flere valg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"quantity": {
|
||||||
|
"reduce": {
|
||||||
|
"accessibilityLabel": "Reduser valg til {{amount}}",
|
||||||
|
"accessibilityHint": "Minimum antall valg nådd, har {{amount}}"
|
||||||
|
},
|
||||||
|
"increase": {
|
||||||
|
"accessibilityLabel": "Reduser valg til {{amount}}",
|
||||||
|
"accessibilityHint": "Maksimum antall valg nådd, har {{amount}}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"multiple": {
|
||||||
|
"heading": "Valg type",
|
||||||
|
"options": {
|
||||||
|
"single": "Ett valg",
|
||||||
|
"multiple": "Flere valg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"expiration": {
|
||||||
|
"heading": "Gyldighet",
|
||||||
|
"options": {
|
||||||
|
"300": "5 minutter",
|
||||||
|
"1800": "30 minutter",
|
||||||
|
"3600": "1 time",
|
||||||
|
"21600": "6 timer",
|
||||||
|
"86400": "1 dag",
|
||||||
|
"259200": "3 dager",
|
||||||
|
"604800": "7 dager"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"actions": {
|
||||||
|
"attachment": {
|
||||||
|
"accessibilityLabel": "Last opp vedlegg",
|
||||||
|
"accessibilityHint": "Avstemmingsfunksjonen blir deaktivert når der er noen vedlegg",
|
||||||
|
"failed": {
|
||||||
|
"alert": {
|
||||||
|
"title": "Opplasting feilet",
|
||||||
|
"button": "Prøv igjen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"poll": {
|
||||||
|
"accessibilityLabel": "Legg til avstemning",
|
||||||
|
"accessibilityHint": "Vedlegg vil bli deaktivert når avstemningen er aktiv"
|
||||||
|
},
|
||||||
|
"visibility": {
|
||||||
|
"accessibilityLabel": "Tut-synlighet er {{visibility}}",
|
||||||
|
"title": "Tut-synlighet",
|
||||||
|
"options": {
|
||||||
|
"public": "Offentlig",
|
||||||
|
"unlisted": "Uoppført",
|
||||||
|
"private": "Kun følgere",
|
||||||
|
"direct": "Direktemelding"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spoiler": {
|
||||||
|
"accessibilityLabel": "Spoiler"
|
||||||
|
},
|
||||||
|
"emoji": {
|
||||||
|
"accessibilityLabel": "Legg til emoji",
|
||||||
|
"accessibilityHint": "Åpne emoji-valgpanel, sveip horisontalt for å endre side"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"drafts_one": "Utkast ({{count}})",
|
||||||
|
"drafts_other": "Utkast ({{count}})"
|
||||||
|
},
|
||||||
|
"editAttachment": {
|
||||||
|
"header": {
|
||||||
|
"title": "Rediger vedlegg",
|
||||||
|
"right": {
|
||||||
|
"accessibilityLabel": "Lagre redigering av vedlegg",
|
||||||
|
"failed": {
|
||||||
|
"title": "Redigering mislyktes",
|
||||||
|
"button": "Prøv igjen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"altText": {
|
||||||
|
"heading": "Beskriv media for synshemmede",
|
||||||
|
"placeholder": "Du kan legge til en beskrivelse, noen ganger kalt alt-tekst, på dine medier slik at de er tilgjengelige for enda flere mennesker, også for dem som er blinde eller svaksynte.\n\nGode beskrivelser er konkret, men presenterer hva som er i dine medier nøyaktig nok til å forstå konteksten."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"draftsList": {
|
||||||
|
"header": {
|
||||||
|
"title": "Utkast"
|
||||||
|
},
|
||||||
|
"warning": "Utkast lagres bare lokalt, og kan ved uhell gå tapt. Bruk ikke utkast til langtidslagring.",
|
||||||
|
"content": {
|
||||||
|
"accessibilityHint": "Lagret utkast, trykk for å redigere dette utkastet",
|
||||||
|
"textEmpty": "Innhold er tomt"
|
||||||
|
},
|
||||||
|
"checkAttachment": "Sjekker vedlegg på serveren..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"content": {
|
||||||
|
"actions": {
|
||||||
|
"accessibilityLabel": "Flere handlinger med dette bildet",
|
||||||
|
"accessibilityHint": "Du kan lagre eller dele dette bildet"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"save": "Lagre bilde",
|
||||||
|
"share": "Del bilde"
|
||||||
|
},
|
||||||
|
"save": {
|
||||||
|
"succeed": "Bilde lagret",
|
||||||
|
"failed": "Lagring av bilde feilet"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,475 @@
|
||||||
|
{
|
||||||
|
"tabs": {
|
||||||
|
"local": {
|
||||||
|
"name": "Følger",
|
||||||
|
"options": {
|
||||||
|
"showBoosts": "Vis booster",
|
||||||
|
"showReplies": "Vis svar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"public": {
|
||||||
|
"segments": {
|
||||||
|
"federated": "Føderert",
|
||||||
|
"local": "Lokal",
|
||||||
|
"trending": "Populært"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"name": "Varsler"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"common": {
|
||||||
|
"search": {
|
||||||
|
"accessibilityLabel": "Søk",
|
||||||
|
"accessibilityHint": "Søk etter emneknagger, brukere eller tuter"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"notifications": {
|
||||||
|
"filters": {
|
||||||
|
"accessibilityLabel": "Filter",
|
||||||
|
"accessibilityHint": "Filtrer viste varslingstyper",
|
||||||
|
"title": "Vis varsler"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"me": {
|
||||||
|
"stacks": {
|
||||||
|
"bookmarks": {
|
||||||
|
"name": "Bokmerker"
|
||||||
|
},
|
||||||
|
"conversations": {
|
||||||
|
"name": "Direktemeldinger"
|
||||||
|
},
|
||||||
|
"favourites": {
|
||||||
|
"name": "Favoritter"
|
||||||
|
},
|
||||||
|
"followedTags": {
|
||||||
|
"name": "Fulgte emneknagger"
|
||||||
|
},
|
||||||
|
"fontSize": {
|
||||||
|
"name": "Skriftstørrelse for tut"
|
||||||
|
},
|
||||||
|
"language": {
|
||||||
|
"name": "Språk"
|
||||||
|
},
|
||||||
|
"list": {
|
||||||
|
"name": "Liste: {{list}}"
|
||||||
|
},
|
||||||
|
"listAccounts": {
|
||||||
|
"name": "Brukere i listen: {{list}}"
|
||||||
|
},
|
||||||
|
"listAdd": {
|
||||||
|
"name": "Opprett liste"
|
||||||
|
},
|
||||||
|
"listEdit": {
|
||||||
|
"name": "Rediger detaljer"
|
||||||
|
},
|
||||||
|
"lists": {
|
||||||
|
"name": "Lister"
|
||||||
|
},
|
||||||
|
"push": {
|
||||||
|
"name": "Pushvarsling"
|
||||||
|
},
|
||||||
|
"preferences": {
|
||||||
|
"name": "Brukervalg"
|
||||||
|
},
|
||||||
|
"preferencesFilters": {
|
||||||
|
"name": "Alle innholdsfiltre"
|
||||||
|
},
|
||||||
|
"preferencesFilterAdd": {
|
||||||
|
"name": "Opprett Filter"
|
||||||
|
},
|
||||||
|
"preferencesFilterEdit": {
|
||||||
|
"name": "Rediger Filter"
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"name": "Rediger Profil"
|
||||||
|
},
|
||||||
|
"profileName": {
|
||||||
|
"name": "Rediger visningsnavn"
|
||||||
|
},
|
||||||
|
"profileNote": {
|
||||||
|
"name": "Rediger beskrivelse"
|
||||||
|
},
|
||||||
|
"profileFields": {
|
||||||
|
"name": "Rediger metadata"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"name": "Appinnstillinger"
|
||||||
|
},
|
||||||
|
"switch": {
|
||||||
|
"name": "Bytt konto"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fontSize": {
|
||||||
|
"demo": "<p>Dette er en demotut😊. Du kan velge flere alternativer nedenfor.<br /><br />Denne innstillingen påvirker bare hovedinnholdet i tuter, men ikke andre skriftstørrelser.</p>",
|
||||||
|
"sizes": {
|
||||||
|
"S": "S",
|
||||||
|
"M": "M - Standard",
|
||||||
|
"L": "L",
|
||||||
|
"XL": "XL",
|
||||||
|
"XXL": "XXL"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"listAccounts": {
|
||||||
|
"heading": "Administrer brukere",
|
||||||
|
"error": "Slett bruker fra listen",
|
||||||
|
"empty": "Ingen bruker lagt til i denne listen"
|
||||||
|
},
|
||||||
|
"listEdit": {
|
||||||
|
"heading": "Rediger detaljer",
|
||||||
|
"title": "Emne",
|
||||||
|
"repliesPolicy": {
|
||||||
|
"heading": "Vis svar:",
|
||||||
|
"options": {
|
||||||
|
"none": "Ingen",
|
||||||
|
"list": "Medlemmer fra listen",
|
||||||
|
"followed": "Enhver fulgt bruker"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"listDelete": {
|
||||||
|
"heading": "Slett liste",
|
||||||
|
"confirm": {
|
||||||
|
"title": "Slett listen \"{{list}}\"?",
|
||||||
|
"message": "Denne handlingen kan ikke gjenopprettes."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"preferences": {
|
||||||
|
"visibility": {
|
||||||
|
"title": "Standard synlighet for post",
|
||||||
|
"options": {
|
||||||
|
"public": "Offentlig",
|
||||||
|
"unlisted": "Uoppført",
|
||||||
|
"private": "Kun følgere"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sensitive": {
|
||||||
|
"title": "Marker alltid media som sensitivt"
|
||||||
|
},
|
||||||
|
"media": {
|
||||||
|
"title": "Visning av media",
|
||||||
|
"options": {
|
||||||
|
"default": "Skjul media som er merket som sensitivt",
|
||||||
|
"show_all": "Vis alltid media",
|
||||||
|
"hide_all": "Skjul alltid media"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"spoilers": {
|
||||||
|
"title": "Utvid alltid tuter som er merket med innholdsadvarsler"
|
||||||
|
},
|
||||||
|
"autoplay_gifs": {
|
||||||
|
"title": "Autostart GIF i tuter"
|
||||||
|
},
|
||||||
|
"filters": {
|
||||||
|
"title": "Innholdsfiltre",
|
||||||
|
"content": "{{count}} aktive"
|
||||||
|
},
|
||||||
|
"web_only": {
|
||||||
|
"title": "Oppdater innstillinger",
|
||||||
|
"description": "Innstillingene nedenfor kan kun oppdateres ved hjelp av web-grensesnittet"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"preferencesFilters": {
|
||||||
|
"expired": "Utløpt",
|
||||||
|
"keywords_one": "{{count}} nøkkelord",
|
||||||
|
"keywords_other": "{{count}} nøkkelord",
|
||||||
|
"statuses_one": "{{count}} tut",
|
||||||
|
"statuses_other": "{{count}} tut",
|
||||||
|
"context": "Gjelder i <0 />",
|
||||||
|
"contexts": {
|
||||||
|
"home": "følgende og lister",
|
||||||
|
"notifications": "varsler",
|
||||||
|
"public": "føderert",
|
||||||
|
"thread": "samtale",
|
||||||
|
"account": "profil"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"preferencesFilter": {
|
||||||
|
"name": "Navn",
|
||||||
|
"expiration": "Utløper",
|
||||||
|
"expirationOptions": {
|
||||||
|
"0": "Aldri",
|
||||||
|
"1800": "Etter 30 minutter",
|
||||||
|
"3600": "Etter 1 time",
|
||||||
|
"43200": "Etter 12 timer",
|
||||||
|
"86400": "Etter 1 dag",
|
||||||
|
"604800": "Etter 1 uke",
|
||||||
|
"18144000": "Etter 1 måned"
|
||||||
|
},
|
||||||
|
"context": "Gjelder i",
|
||||||
|
"contexts": {
|
||||||
|
"home": "Følgende og lister",
|
||||||
|
"notifications": "Varsel",
|
||||||
|
"public": "Føderert tidlinje",
|
||||||
|
"thread": "Samtalevisning",
|
||||||
|
"account": "Profil visning"
|
||||||
|
},
|
||||||
|
"action": "Når samsvarende",
|
||||||
|
"actions": {
|
||||||
|
"warn": "Kollapset, men kan vises",
|
||||||
|
"hide": "Skjult fullstendig"
|
||||||
|
},
|
||||||
|
"keywords": "Treff for disse nøkkelordene",
|
||||||
|
"keyword": "Nøkkelord",
|
||||||
|
"statuses": "Treff disse tutene"
|
||||||
|
},
|
||||||
|
"profile": {
|
||||||
|
"feedback": {
|
||||||
|
"succeed": "{{type}} oppdatert",
|
||||||
|
"failed": "{{type}} oppdatering feilet, prøv igjen"
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"name": {
|
||||||
|
"title": "Visningsnavn"
|
||||||
|
},
|
||||||
|
"avatar": {
|
||||||
|
"title": "Profilbilde",
|
||||||
|
"description": "Vil bli nedskalert til 400 x 400 px"
|
||||||
|
},
|
||||||
|
"header": {
|
||||||
|
"title": "Fane",
|
||||||
|
"description": "Vil bli nedskalert til 1500x500px"
|
||||||
|
},
|
||||||
|
"note": {
|
||||||
|
"title": "Beskrivelse"
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"title": "Metadata",
|
||||||
|
"total_one": "{{count}} felt",
|
||||||
|
"total_other": "{{count}} felt"
|
||||||
|
},
|
||||||
|
"lock": {
|
||||||
|
"title": "Lås konto",
|
||||||
|
"description": "Krever at du godkjenner følgere manuelt"
|
||||||
|
},
|
||||||
|
"bot": {
|
||||||
|
"title": "Bot konto",
|
||||||
|
"description": "Denne kontoen utfører i hovedsak automatiserte handlinger og blir kanskje ikke holdt øye med"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"fields": {
|
||||||
|
"group": "Gruppe {{index}}",
|
||||||
|
"label": "Etikett",
|
||||||
|
"content": "Innhold"
|
||||||
|
},
|
||||||
|
"mediaSelectionFailed": "Bildebehandling mislyktes. Vennligst prøv igjen."
|
||||||
|
},
|
||||||
|
"push": {
|
||||||
|
"notAvailable": "Din telefon støtter ikke tooot's push-varsling",
|
||||||
|
"enable": {
|
||||||
|
"direct": "Aktiver push-varsler",
|
||||||
|
"settings": "Aktiver i innstillinger"
|
||||||
|
},
|
||||||
|
"missingServerKey": {
|
||||||
|
"message": "Feil på tjener for push-tjeneste",
|
||||||
|
"description": "Vennligst kontakt din serveradministrator for å konfigurere push-støtte"
|
||||||
|
},
|
||||||
|
"global": {
|
||||||
|
"heading": "Aktiver for {{acct}}",
|
||||||
|
"description": "Meldinger blir sendt gjennom toot's server"
|
||||||
|
},
|
||||||
|
"decode": {
|
||||||
|
"heading": "Meldingsdetaljer",
|
||||||
|
"description": "Meldinger sendt gjennom toots server er kryptert, men du kan velge å dekode meldingen på serveren. Vår server er åpen kildekode og har ingen logging."
|
||||||
|
},
|
||||||
|
"default": {
|
||||||
|
"heading": "Standard"
|
||||||
|
},
|
||||||
|
"follow": {
|
||||||
|
"heading": "Ny følger"
|
||||||
|
},
|
||||||
|
"follow_request": {
|
||||||
|
"heading": "Følgerforespørsel"
|
||||||
|
},
|
||||||
|
"favourite": {
|
||||||
|
"heading": "Favorisert"
|
||||||
|
},
|
||||||
|
"reblog": {
|
||||||
|
"heading": "Boostet"
|
||||||
|
},
|
||||||
|
"mention": {
|
||||||
|
"heading": "Nevnte deg"
|
||||||
|
},
|
||||||
|
"poll": {
|
||||||
|
"heading": "Oppdateringer om avstemning"
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"heading": "Tut fra påmeldte brukere"
|
||||||
|
},
|
||||||
|
"update": {
|
||||||
|
"heading": "%s er redigert"
|
||||||
|
},
|
||||||
|
"admin.sign_up": {
|
||||||
|
"heading": "Administrer: registrer deg"
|
||||||
|
},
|
||||||
|
"admin.report": {
|
||||||
|
"heading": "Administrer: rapporter"
|
||||||
|
},
|
||||||
|
"howitworks": "Lær hvordan ruting virker"
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"announcements": {
|
||||||
|
"content": {
|
||||||
|
"unread": "{{amount}} ulest",
|
||||||
|
"read": "Alt lest",
|
||||||
|
"empty": "Ingen"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"push": {
|
||||||
|
"content_true": "Aktivert",
|
||||||
|
"content_false": "Deaktivert"
|
||||||
|
},
|
||||||
|
"logout": {
|
||||||
|
"button": "Logg ut",
|
||||||
|
"alert": {
|
||||||
|
"title": "Logge ut?",
|
||||||
|
"message": "Etter å ha logget ut, må du logge på igjen",
|
||||||
|
"buttons": {
|
||||||
|
"logout": "Logg ut"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"theme": {
|
||||||
|
"heading": "Utseende",
|
||||||
|
"options": {
|
||||||
|
"auto": "Som system",
|
||||||
|
"light": "Lyst tema",
|
||||||
|
"dark": "Mørkt tema"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"darkTheme": {
|
||||||
|
"heading": "Mørkt tema",
|
||||||
|
"options": {
|
||||||
|
"lighter": "Standard",
|
||||||
|
"darker": "Helt svart"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"browser": {
|
||||||
|
"heading": "Åpning av lenke",
|
||||||
|
"options": {
|
||||||
|
"internal": "I appen",
|
||||||
|
"external": "Bruk nettleser"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"autoplayGifv": {
|
||||||
|
"heading": "Autostart GIF i tuter"
|
||||||
|
},
|
||||||
|
"feedback": {
|
||||||
|
"heading": "Funksjonsforespørsler"
|
||||||
|
},
|
||||||
|
"support": {
|
||||||
|
"heading": "Støtt tooot"
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"heading": "Kontakt tooot"
|
||||||
|
},
|
||||||
|
"version": "Versjon v{{version}}",
|
||||||
|
"instanceVersion": "Mastodon versjon v{{version}}"
|
||||||
|
},
|
||||||
|
"switch": {
|
||||||
|
"existing": "Velg fra innlogget",
|
||||||
|
"new": "Logg inn på instans"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"shared": {
|
||||||
|
"account": {
|
||||||
|
"actions": {
|
||||||
|
"accessibilityLabel": "Handlinger for bruker {{user}}",
|
||||||
|
"accessibilityHint": "Du kan dempe, blokkere, rapportere eller dele denne brukeren"
|
||||||
|
},
|
||||||
|
"followed_by": " følger deg",
|
||||||
|
"moved": "Bruker flyttet",
|
||||||
|
"created_at": "Ble med: {{date}}",
|
||||||
|
"summary": {
|
||||||
|
"statuses_count": "{{count}} tut"
|
||||||
|
},
|
||||||
|
"toots": {
|
||||||
|
"default": "Tuter",
|
||||||
|
"all": "Tuter og svar"
|
||||||
|
},
|
||||||
|
"suspended": "Konto suspendert av moderatorene på serveren din"
|
||||||
|
},
|
||||||
|
"accountInLists": {
|
||||||
|
"name": "Lister av @{{username}}",
|
||||||
|
"inLists": "I liste",
|
||||||
|
"notInLists": "Andre lister"
|
||||||
|
},
|
||||||
|
"attachments": {
|
||||||
|
"name": "<0 /><1>'s media</1>"
|
||||||
|
},
|
||||||
|
"filter": {
|
||||||
|
"name": "Legg til filter",
|
||||||
|
"existed": "Finnes i disse filtrene"
|
||||||
|
},
|
||||||
|
"history": {
|
||||||
|
"name": "Rediger historikk"
|
||||||
|
},
|
||||||
|
"report": {
|
||||||
|
"name": "Rapporter {{acct}}",
|
||||||
|
"report": "Rapporter",
|
||||||
|
"forward": {
|
||||||
|
"heading": "Anonymt videresendt til ekstern server {{instance}}"
|
||||||
|
},
|
||||||
|
"reasons": {
|
||||||
|
"heading": "Hva skjer med denne kontoen?",
|
||||||
|
"spam": "Det er søppelpost",
|
||||||
|
"other": "Det er noe annet",
|
||||||
|
"violation": "Det bryter serverregler"
|
||||||
|
},
|
||||||
|
"comment": {
|
||||||
|
"heading": "Noe annet du vil legge til?"
|
||||||
|
},
|
||||||
|
"violatedRules": {
|
||||||
|
"heading": "Det bryter serverregler"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"header": {
|
||||||
|
"prefix": "Søker",
|
||||||
|
"placeholder": "etter..."
|
||||||
|
},
|
||||||
|
"empty": {
|
||||||
|
"general": "Angi nøkkelord for å søke etter <bold>$t(screenTabs:shared.search.sections.accounts)</bold>、<bold>$t(screenTabs:shared.search.sections.hashtags)</bold> eller <bold>$t(screenTabs:shared.search.sections.statuses)</bold>",
|
||||||
|
"advanced": {
|
||||||
|
"header": "Avansert søk",
|
||||||
|
"example": {
|
||||||
|
"account": "$t(shared.search.header.prefix) $t(shared.search.sections.accounts)",
|
||||||
|
"hashtag": "$t(shared.search.header.prefix) $t(shared.search.sections.hashtags)",
|
||||||
|
"statusLink": "$t(shared.search.header.prefix) $t(shared.search.sections.statuses)",
|
||||||
|
"accountLink": "$t(shared.search.header.prefix) $t(shared.search.sections.accounts)"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"trending": {
|
||||||
|
"tags": "Populære emner"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sections": {
|
||||||
|
"accounts": "Bruker",
|
||||||
|
"hashtags": "Emneknagg",
|
||||||
|
"statuses": "Tut"
|
||||||
|
},
|
||||||
|
"notFound": "Finner ikke <bold>{{searchTerm}}</bold> relatert til {{type}}",
|
||||||
|
"noResult": "Kan ikke finne noe, vennligst prøv et annet begrep"
|
||||||
|
},
|
||||||
|
"toot": {
|
||||||
|
"name": "Diskusjoner",
|
||||||
|
"remoteFetch": {
|
||||||
|
"title": "Inneholder eksternt innhold",
|
||||||
|
"message": "Føderert innhold er ikke alltid tilgjengelig på lokal forekomst. Dette innholdet hentes fra ekstern forekomst og merkes. Du kan samhandle med disse innholdet som vanlig."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"accounts": {
|
||||||
|
"following": "Følger {{count}}",
|
||||||
|
"followers": "{{count}} følgere"
|
||||||
|
},
|
||||||
|
"statuses": {
|
||||||
|
"reblogged_by": "{{count}} boostet",
|
||||||
|
"favourited_by": "{{count}} som favoritt"
|
||||||
|
},
|
||||||
|
"resultIncomplete": "Resultater fra en ekstern instans er ufullstendig"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -33,7 +33,7 @@
|
||||||
"poll": "Опитування, у якому ви голосували, закінчилося",
|
"poll": "Опитування, у якому ви голосували, закінчилося",
|
||||||
"reblog": {
|
"reblog": {
|
||||||
"default": "{{name}} передмухує",
|
"default": "{{name}} передмухує",
|
||||||
"myself": "",
|
"myself": "Передмухнуто мною",
|
||||||
"notification": "{{name}} передмухує ваш дмух"
|
"notification": "{{name}} передмухує ваш дмух"
|
||||||
},
|
},
|
||||||
"update": "Передмух був відредагований",
|
"update": "Передмух був відредагований",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import Button from '@components/Button'
|
import Button from '@components/Button'
|
||||||
|
import GracefullyImage from '@components/GracefullyImage'
|
||||||
import haptics from '@components/haptics'
|
import haptics from '@components/haptics'
|
||||||
import { Loading } from '@components/Loading'
|
import { Loading } from '@components/Loading'
|
||||||
import { ParseHTML } from '@components/Parse'
|
import { ParseHTML } from '@components/Parse'
|
||||||
|
@ -6,7 +7,6 @@ import RelativeTime from '@components/RelativeTime'
|
||||||
import CustomText from '@components/Text'
|
import CustomText from '@components/Text'
|
||||||
import { BlurView } from '@react-native-community/blur'
|
import { BlurView } from '@react-native-community/blur'
|
||||||
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
|
import { useAccessibility } from '@utils/accessibility/AccessibilityManager'
|
||||||
import { connectMedia } from '@utils/api/helpers/connect'
|
|
||||||
import { RootStackScreenProps } from '@utils/navigation/navigators'
|
import { RootStackScreenProps } from '@utils/navigation/navigators'
|
||||||
import { useAnnouncementMutation, useAnnouncementQuery } from '@utils/queryHooks/announcement'
|
import { useAnnouncementMutation, useAnnouncementQuery } from '@utils/queryHooks/announcement'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
|
@ -22,7 +22,6 @@ import {
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
View
|
View
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
import FastImage from 'react-native-fast-image'
|
|
||||||
import { FlatList, ScrollView } from 'react-native-gesture-handler'
|
import { FlatList, ScrollView } from 'react-native-gesture-handler'
|
||||||
import { SafeAreaView } from 'react-native-safe-area-context'
|
import { SafeAreaView } from 'react-native-safe-area-context'
|
||||||
|
|
||||||
|
@ -139,12 +138,13 @@ const ScreenAnnouncements: React.FC<RootStackScreenProps<'Screen-Announcements'>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{reaction.url ? (
|
{reaction.url ? (
|
||||||
<FastImage
|
<GracefullyImage
|
||||||
source={connectMedia({
|
sources={{
|
||||||
uri: reduceMotionEnabled ? reaction.static_url : reaction.url
|
default: { uri: reaction.url },
|
||||||
})}
|
static: { uri: reaction.static_url }
|
||||||
style={{
|
}}
|
||||||
width: StyleConstants.Font.LineHeight.M + 3,
|
dimension={{
|
||||||
|
width: StyleConstants.Font.LineHeight.M,
|
||||||
height: StyleConstants.Font.LineHeight.M
|
height: StyleConstants.Font.LineHeight.M
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -9,10 +9,10 @@ import { ScreenComposeStackScreenProps } from '@utils/navigation/navigators'
|
||||||
import { getAccountStorage, setAccountStorage, useAccountStorage } from '@utils/storage/actions'
|
import { getAccountStorage, setAccountStorage, useAccountStorage } from '@utils/storage/actions'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
|
import { Image } from 'expo-image'
|
||||||
import React, { useContext, useEffect, useState } from 'react'
|
import React, { useContext, useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Dimensions, Modal, Pressable, View } from 'react-native'
|
import { Dimensions, Modal, Pressable, View } from 'react-native'
|
||||||
import FastImage from 'react-native-fast-image'
|
|
||||||
import ComposeContext from './utils/createContext'
|
import ComposeContext from './utils/createContext'
|
||||||
import { formatText } from './utils/processText'
|
import { formatText } from './utils/processText'
|
||||||
import { ComposeStateDraft, ExtendedAttachment } from './utils/types'
|
import { ComposeStateDraft, ExtendedAttachment } from './utils/types'
|
||||||
|
@ -140,7 +140,7 @@ const ComposeDraftsList: React.FC<ScreenComposeStackScreenProps<'Screen-Compose-
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{item.attachments.uploads.map((attachment, index) => (
|
{item.attachments.uploads.map((attachment, index) => (
|
||||||
<FastImage
|
<Image
|
||||||
key={index}
|
key={index}
|
||||||
style={{
|
style={{
|
||||||
width:
|
width:
|
||||||
|
|
|
@ -11,10 +11,10 @@ import { featureCheck } from '@utils/helpers/featureCheck'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import layoutAnimation from '@utils/styles/layoutAnimation'
|
import layoutAnimation from '@utils/styles/layoutAnimation'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
|
import { Image } from 'expo-image'
|
||||||
import React, { RefObject, useContext, useEffect, useRef } from 'react'
|
import React, { RefObject, useContext, useEffect, useRef } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { FlatList, Pressable, StyleSheet, View } from 'react-native'
|
import { FlatList, Pressable, StyleSheet, View } from 'react-native'
|
||||||
import FastImage from 'react-native-fast-image'
|
|
||||||
import ComposeContext from '../../utils/createContext'
|
import ComposeContext from '../../utils/createContext'
|
||||||
import { ExtendedAttachment } from '../../utils/types'
|
import { ExtendedAttachment } from '../../utils/types'
|
||||||
import chooseAndUploadAttachment from './addAttachment'
|
import chooseAndUploadAttachment from './addAttachment'
|
||||||
|
@ -104,9 +104,7 @@ const ComposeAttachments: React.FC<Props> = ({ accessibleRefAttachments }) => {
|
||||||
width: calculateWidth(item)
|
width: calculateWidth(item)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FastImage
|
<Image
|
||||||
enterTransition='fadeIn'
|
|
||||||
transitionDuration={60}
|
|
||||||
style={{ width: '100%', height: '100%' }}
|
style={{ width: '100%', height: '100%' }}
|
||||||
source={
|
source={
|
||||||
item.local?.thumbnail
|
item.local?.thumbnail
|
||||||
|
|
|
@ -193,10 +193,10 @@ const ScreenImagesViewer = ({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<GracefullyImage
|
<GracefullyImage
|
||||||
uri={{
|
sources={{
|
||||||
preview: item.preview_url,
|
preview: { uri: item.preview_url },
|
||||||
remote: item.remote_url,
|
default: { uri: item.url },
|
||||||
original: item.url
|
remote: { uri: item.remote_url }
|
||||||
}}
|
}}
|
||||||
dimension={{
|
dimension={{
|
||||||
width:
|
width:
|
||||||
|
@ -208,6 +208,7 @@ const ScreenImagesViewer = ({
|
||||||
? WINDOW_HEIGHT
|
? WINDOW_HEIGHT
|
||||||
: (WINDOW_WIDTH / imageWidth) * imageHeight
|
: (WINDOW_WIDTH / imageWidth) * imageHeight
|
||||||
}}
|
}}
|
||||||
|
enableLiveTextInteraction
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,8 +16,8 @@ import { setAccountStorage, useAccountStorage, useGlobalStorage } from '@utils/s
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import layoutAnimation from '@utils/styles/layoutAnimation'
|
import layoutAnimation from '@utils/styles/layoutAnimation'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
|
import * as Crypto from 'expo-crypto'
|
||||||
import * as Notifications from 'expo-notifications'
|
import * as Notifications from 'expo-notifications'
|
||||||
import * as Random from 'expo-random'
|
|
||||||
import * as WebBrowser from 'expo-web-browser'
|
import * as WebBrowser from 'expo-web-browser'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
@ -164,16 +164,15 @@ const TabMePush: React.FC = () => {
|
||||||
url: `push/unsubscribe/${pushPath}`
|
url: `push/unsubscribe/${pushPath}`
|
||||||
})
|
})
|
||||||
|
|
||||||
|
setAccountStorage([{ key: 'push', value: { ...push, global: false } }])
|
||||||
if (Platform.OS === 'android') {
|
if (Platform.OS === 'android') {
|
||||||
Notifications.deleteNotificationChannelGroupAsync(accountFull)
|
Notifications.deleteNotificationChannelGroupAsync(accountFull)
|
||||||
}
|
}
|
||||||
|
|
||||||
setAccountStorage([{ key: 'push', value: { ...push, global: false } }])
|
|
||||||
} else {
|
} else {
|
||||||
// Fix a bug for some users of v4.8.0
|
// Fix a bug for some users of v4.8.0
|
||||||
let authKey = push.key
|
let authKey = push.key
|
||||||
if (push.key?.length <= 10) {
|
if (push.key?.length <= 10) {
|
||||||
authKey = fromByteArray(Random.getRandomBytes(16))
|
authKey = fromByteArray(Crypto.getRandomBytes(16))
|
||||||
}
|
}
|
||||||
// Turning on
|
// Turning on
|
||||||
const randomPath = (Math.random() + 1).toString(36).substring(2)
|
const randomPath = (Math.random() + 1).toString(36).substring(2)
|
||||||
|
@ -182,7 +181,7 @@ const TabMePush: React.FC = () => {
|
||||||
|
|
||||||
const body: {
|
const body: {
|
||||||
subscription: any
|
subscription: any
|
||||||
alerts: Mastodon.PushSubscription['alerts']
|
data: { alerts: Mastodon.PushSubscription['alerts'] }
|
||||||
} = {
|
} = {
|
||||||
subscription: {
|
subscription: {
|
||||||
endpoint,
|
endpoint,
|
||||||
|
@ -192,7 +191,7 @@ const TabMePush: React.FC = () => {
|
||||||
auth: authKey
|
auth: authKey
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
alerts: push.alerts
|
data: { alerts: push.alerts }
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await apiInstance<Mastodon.PushSubscription>({
|
const res = await apiInstance<Mastodon.PushSubscription>({
|
||||||
|
@ -239,7 +238,6 @@ const TabMePush: React.FC = () => {
|
||||||
setAccountStorage([
|
setAccountStorage([
|
||||||
{ key: 'push', value: { ...push, global: true, key: authKey } }
|
{ key: 'push', value: { ...push, global: true, key: authKey } }
|
||||||
])
|
])
|
||||||
|
|
||||||
if (Platform.OS === 'android') {
|
if (Platform.OS === 'android') {
|
||||||
setChannels(true)
|
setChannels(true)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,13 @@ import { LOCALES } from '@i18n/locales'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
import { connectVerify } from '@utils/api/helpers/connect'
|
import { connectVerify } from '@utils/api/helpers/connect'
|
||||||
import { androidActionSheetStyles } from '@utils/helpers/androidActionSheetStyles'
|
import { androidActionSheetStyles } from '@utils/helpers/androidActionSheetStyles'
|
||||||
|
import { GLOBAL } from '@utils/storage'
|
||||||
import { useGlobalStorage } from '@utils/storage/actions'
|
import { useGlobalStorage } from '@utils/storage/actions'
|
||||||
import { useTheme } from '@utils/styles/ThemeManager'
|
import { useTheme } from '@utils/styles/ThemeManager'
|
||||||
import * as Localization from 'expo-localization'
|
import * as Localization from 'expo-localization'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { Linking, Platform } from 'react-native'
|
import { Linking, Platform } from 'react-native'
|
||||||
import { GLOBAL } from '../../../../App'
|
|
||||||
import { mapFontsizeToName } from '../SettingsFontsize'
|
import { mapFontsizeToName } from '../SettingsFontsize'
|
||||||
|
|
||||||
const SettingsApp: React.FC = () => {
|
const SettingsApp: React.FC = () => {
|
||||||
|
|
|
@ -82,15 +82,25 @@ const AccountAttachments: React.FC = () => {
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<GracefullyImage
|
<GracefullyImage
|
||||||
uri={{
|
sources={{
|
||||||
original:
|
preview: {
|
||||||
item.media_attachments[0]?.preview_url || item.media_attachments[0]?.url,
|
uri: item.media_attachments[0]?.preview_url,
|
||||||
remote: item.media_attachments[0]?.remote_url
|
width: item.media_attachments[0]?.meta?.small?.width,
|
||||||
|
height: item.media_attachments[0]?.meta?.small?.height
|
||||||
|
},
|
||||||
|
default: {
|
||||||
|
uri: item.media_attachments[0]?.url,
|
||||||
|
width: item.media_attachments[0]?.meta?.original?.width,
|
||||||
|
height: item.media_attachments[0]?.meta?.original?.height
|
||||||
|
},
|
||||||
|
remote: {
|
||||||
|
uri: item.media_attachments[0]?.remote_url,
|
||||||
|
width: item.media_attachments[0]?.meta?.original?.width,
|
||||||
|
height: item.media_attachments[0]?.meta?.original?.height
|
||||||
|
},
|
||||||
|
blurhash: item.media_attachments[0]?.blurhash
|
||||||
}}
|
}}
|
||||||
blurhash={
|
dimension={{ width, height: width }}
|
||||||
item.media_attachments[0] && (item.media_attachments[0].blurhash || undefined)
|
|
||||||
}
|
|
||||||
dimension={{ width: width, height: width }}
|
|
||||||
style={{ marginLeft: StyleConstants.Spacing.Global.PagePadding }}
|
style={{ marginLeft: StyleConstants.Spacing.Global.PagePadding }}
|
||||||
onPress={() => navigation.push('Tab-Shared-Toot', { toot: item })}
|
onPress={() => navigation.push('Tab-Shared-Toot', { toot: item })}
|
||||||
dim
|
dim
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import GracefullyImage from '@components/GracefullyImage'
|
import GracefullyImage from '@components/GracefullyImage'
|
||||||
import navigationRef from '@utils/navigation/navigationRef'
|
import navigationRef from '@utils/navigation/navigationRef'
|
||||||
import { useGlobalStorage } from '@utils/storage/actions'
|
|
||||||
import React, { useContext } from 'react'
|
import React, { useContext } from 'react'
|
||||||
import { Dimensions, Image } from 'react-native'
|
import { Dimensions, Image } from 'react-native'
|
||||||
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
||||||
|
@ -11,11 +10,9 @@ const AccountHeader: React.FC = () => {
|
||||||
|
|
||||||
const topInset = useSafeAreaInsets().top
|
const topInset = useSafeAreaInsets().top
|
||||||
|
|
||||||
useGlobalStorage.string('account.active')
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GracefullyImage
|
<GracefullyImage
|
||||||
uri={{ original: account?.header, static: account?.header_static }}
|
sources={{ default: { uri: account?.header }, static: { uri: account?.header_static } }}
|
||||||
style={{ height: Dimensions.get('window').width / 3 + topInset }}
|
style={{ height: Dimensions.get('window').width / 3 + topInset }}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
if (account) {
|
if (account) {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import Button from '@components/Button'
|
||||||
import menuAt from '@components/contextMenu/at'
|
import menuAt from '@components/contextMenu/at'
|
||||||
import { RelationshipOutgoing } from '@components/Relationship'
|
import { RelationshipOutgoing } from '@components/Relationship'
|
||||||
import { useNavigation } from '@react-navigation/native'
|
import { useNavigation } from '@react-navigation/native'
|
||||||
import { useAccountStorage } from '@utils/storage/actions'
|
import { checkIsMyAccount } from '@utils/helpers/isMyAccount'
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import React, { useContext } from 'react'
|
import React, { useContext } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
@ -56,12 +56,11 @@ const AccountInformationActions: React.FC = () => {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const [accountId] = useAccountStorage.string('auth.account.id')
|
const isMyAccount = checkIsMyAccount(account?.id)
|
||||||
const ownAccount = account?.id === accountId
|
|
||||||
|
|
||||||
const mAt = menuAt({ account })
|
const mAt = menuAt({ account })
|
||||||
|
|
||||||
if (!ownAccount && account) {
|
if (!isMyAccount && account) {
|
||||||
return (
|
return (
|
||||||
<View style={styles.base}>
|
<View style={styles.base}>
|
||||||
{relationship && !relationship.blocked_by ? (
|
{relationship && !relationship.blocked_by ? (
|
||||||
|
|
|
@ -3,7 +3,6 @@ import { useNavigation } from '@react-navigation/native'
|
||||||
import { StackNavigationProp } from '@react-navigation/stack'
|
import { StackNavigationProp } from '@react-navigation/stack'
|
||||||
import navigationRef from '@utils/navigation/navigationRef'
|
import navigationRef from '@utils/navigation/navigationRef'
|
||||||
import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
import { TabLocalStackParamList } from '@utils/navigation/navigators'
|
||||||
import { useAccountStorage } from '@utils/storage/actions'
|
|
||||||
import { StyleConstants } from '@utils/styles/constants'
|
import { StyleConstants } from '@utils/styles/constants'
|
||||||
import React, { useContext } from 'react'
|
import React, { useContext } from 'react'
|
||||||
import AccountContext from '../Context'
|
import AccountContext from '../Context'
|
||||||
|
@ -13,20 +12,13 @@ const AccountInformationAvatar: React.FC = () => {
|
||||||
|
|
||||||
const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>()
|
const navigation = useNavigation<StackNavigationProp<TabLocalStackParamList>>()
|
||||||
|
|
||||||
const [accountAvatarStatic] = useAccountStorage.string('auth.account.avatar_static')
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GracefullyImage
|
<GracefullyImage
|
||||||
key={account?.avatar}
|
style={{ borderRadius: 8, overflow: 'hidden' }}
|
||||||
style={{
|
dimension={{ width: StyleConstants.Avatar.L, height: StyleConstants.Avatar.L }}
|
||||||
borderRadius: 8,
|
sources={{
|
||||||
overflow: 'hidden',
|
default: { uri: account?.avatar },
|
||||||
width: StyleConstants.Avatar.L,
|
static: { uri: account?.avatar_static }
|
||||||
height: StyleConstants.Avatar.L
|
|
||||||
}}
|
|
||||||
uri={{
|
|
||||||
original: account?.avatar || (pageMe ? accountAvatarStatic : undefined),
|
|
||||||
static: account?.avatar_static || (pageMe ? accountAvatarStatic : undefined)
|
|
||||||
}}
|
}}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
if (account) {
|
if (account) {
|
||||||
|
|
|
@ -248,7 +248,11 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
||||||
body: data.map(remote => {
|
body: data.map(remote => {
|
||||||
const localMatch = old?.pages[0].body.find(local => local.uri === remote.uri)
|
const localMatch = old?.pages[0].body.find(local => local.uri === remote.uri)
|
||||||
if (localMatch) {
|
if (localMatch) {
|
||||||
return { ...localMatch, _level: remote._level }
|
return {
|
||||||
|
...localMatch,
|
||||||
|
_level: remote._level,
|
||||||
|
key: `${localMatch.id}_remote`
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return appendRemote.status(remote)
|
return appendRemote.status(remote)
|
||||||
}
|
}
|
||||||
|
@ -275,6 +279,7 @@ const TabSharedToot: React.FC<TabSharedStackScreenProps<'Tab-Shared-Toot'>> = ({
|
||||||
ref={flRef}
|
ref={flRef}
|
||||||
windowSize={5}
|
windowSize={5}
|
||||||
data={query.data?.pages?.[0].body}
|
data={query.data?.pages?.[0].body}
|
||||||
|
extraData={query.dataUpdatedAt}
|
||||||
renderItem={({ item, index }) => {
|
renderItem={({ item, index }) => {
|
||||||
const prev = query.data?.pages[0].body[index - 1]?._level || 0
|
const prev = query.data?.pages[0].body[index - 1]?._level || 0
|
||||||
const curr = item._level || 0
|
const curr = item._level || 0
|
||||||
|
|
|
@ -50,9 +50,9 @@ const ScreenTabs = () => {
|
||||||
return <Icon name='bell' size={size} color={color} />
|
return <Icon name='bell' size={size} color={color} />
|
||||||
case 'Tab-Me':
|
case 'Tab-Me':
|
||||||
return (
|
return (
|
||||||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
<View key={avatarStatic} style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||||||
<GracefullyImage
|
<GracefullyImage
|
||||||
uri={{ original: avatarStatic }}
|
sources={{ default: { uri: avatarStatic } }}
|
||||||
dimension={{ width: size, height: size }}
|
dimension={{ width: size, height: size }}
|
||||||
style={{
|
style={{
|
||||||
borderRadius: size,
|
borderRadius: size,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
import { GLOBAL } from '@utils/storage'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { GLOBAL } from '../../App'
|
|
||||||
import { ctx, handleError, PagedResponse, parseHeaderLinks, userAgent } from './helpers'
|
import { ctx, handleError, PagedResponse, parseHeaderLinks, userAgent } from './helpers'
|
||||||
import { CONNECT_DOMAIN } from './helpers/connect'
|
import { CONNECT_DOMAIN } from './helpers/connect'
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import { mapEnvironment } from '@utils/helpers/checkEnvironment'
|
import { mapEnvironment } from '@utils/helpers/checkEnvironment'
|
||||||
|
import { GLOBAL } from '@utils/storage'
|
||||||
import { setGlobalStorage } from '@utils/storage/actions'
|
import { setGlobalStorage } from '@utils/storage/actions'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import parse from 'url-parse'
|
import parse from 'url-parse'
|
||||||
import { userAgent } from '.'
|
import { userAgent } from '.'
|
||||||
import { GLOBAL } from '../../../App'
|
|
||||||
|
|
||||||
const list = [
|
const list = [
|
||||||
'n61owz4leck',
|
'n61owz4leck',
|
||||||
|
@ -81,19 +81,18 @@ export const CONNECT_DOMAIN = (index?: number) =>
|
||||||
development: 'connect-development.tooot.app'
|
development: 'connect-development.tooot.app'
|
||||||
})
|
})
|
||||||
|
|
||||||
export const connectMedia = ({
|
export const connectMedia = (args?: {
|
||||||
uri
|
|
||||||
}: {
|
|
||||||
uri?: string
|
uri?: string
|
||||||
}): { uri?: string; headers?: { 'x-tooot-domain': string } } => {
|
}): { uri?: string; headers?: { 'x-tooot-domain': string } } => {
|
||||||
if (GLOBAL.connect) {
|
if (GLOBAL.connect) {
|
||||||
if (uri) {
|
if (args?.uri) {
|
||||||
const host = parse(uri).host
|
const host = parse(args.uri).host
|
||||||
return {
|
return {
|
||||||
uri: uri.replace(
|
...args,
|
||||||
|
uri: args.uri.replace(
|
||||||
host,
|
host,
|
||||||
CONNECT_DOMAIN(
|
CONNECT_DOMAIN(
|
||||||
uri
|
args.uri
|
||||||
.split('')
|
.split('')
|
||||||
.map(i => i.charCodeAt(0))
|
.map(i => i.charCodeAt(0))
|
||||||
.reduce((a, b) => a + b, 0) %
|
.reduce((a, b) => a + b, 0) %
|
||||||
|
@ -103,10 +102,10 @@ export const connectMedia = ({
|
||||||
headers: { 'x-tooot-domain': host }
|
headers: { 'x-tooot-domain': host }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return { uri }
|
return { ...args }
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return { uri }
|
return { ...args }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import * as Sentry from '@sentry/react-native'
|
import * as Sentry from '@sentry/react-native'
|
||||||
|
import { GLOBAL } from '@utils/storage'
|
||||||
import { setGlobalStorage } from '@utils/storage/actions'
|
import { setGlobalStorage } from '@utils/storage/actions'
|
||||||
import chalk from 'chalk'
|
import chalk from 'chalk'
|
||||||
import Constants from 'expo-constants'
|
import Constants from 'expo-constants'
|
||||||
import { Platform } from 'react-native'
|
import { Platform } from 'react-native'
|
||||||
import parse from 'url-parse'
|
import parse from 'url-parse'
|
||||||
import { GLOBAL } from '../../../App'
|
|
||||||
|
|
||||||
const userAgent = {
|
const userAgent = {
|
||||||
'User-Agent': `tooot/${Constants.expoConfig?.version} ${Platform.OS}/${Platform.Version}`
|
'User-Agent': `tooot/${Constants.expoConfig?.version} ${Platform.OS}/${Platform.Version}`
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
import { GLOBAL } from '@utils/storage'
|
||||||
import { getAccountDetails } from '@utils/storage/actions'
|
import { getAccountDetails } from '@utils/storage/actions'
|
||||||
import { StorageGlobal } from '@utils/storage/global'
|
import { StorageGlobal } from '@utils/storage/global'
|
||||||
import axios, { AxiosRequestConfig } from 'axios'
|
import axios, { AxiosRequestConfig } from 'axios'
|
||||||
import { GLOBAL } from '../../App'
|
|
||||||
import { ctx, handleError, PagedResponse, parseHeaderLinks, userAgent } from './helpers'
|
import { ctx, handleError, PagedResponse, parseHeaderLinks, userAgent } from './helpers'
|
||||||
import { CONNECT_DOMAIN } from './helpers/connect'
|
import { CONNECT_DOMAIN } from './helpers/connect'
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { getAccountStorage } from '@utils/storage/actions'
|
||||||
|
|
||||||
|
export const checkIsMyAccount = (id?: Mastodon.Account['id']): boolean => {
|
||||||
|
if (!id) return false
|
||||||
|
|
||||||
|
const accountId = getAccountStorage.string('auth.account.id')
|
||||||
|
const accountDomain = getAccountStorage.string('auth.account.domain')
|
||||||
|
return accountId === id || `${accountId}@${accountDomain}` === id
|
||||||
|
}
|
|
@ -9,7 +9,7 @@ export const urlMatcher = (
|
||||||
):
|
):
|
||||||
| {
|
| {
|
||||||
domain: string
|
domain: string
|
||||||
account?: Partial<Pick<Mastodon.Account, 'id' | 'acct' | '_remote'>>
|
account?: Partial<Pick<Mastodon.Account, 'acct' | '_remote'>>
|
||||||
status?: Partial<Pick<Mastodon.Status, 'id' | '_remote'>>
|
status?: Partial<Pick<Mastodon.Status, 'id' | '_remote'>>
|
||||||
}
|
}
|
||||||
| undefined => {
|
| undefined => {
|
||||||
|
@ -24,13 +24,18 @@ export const urlMatcher = (
|
||||||
const _remote = parsed.hostname !== getAccountStorage.string('auth.domain')
|
const _remote = parsed.hostname !== getAccountStorage.string('auth.domain')
|
||||||
|
|
||||||
let statusId: string | undefined
|
let statusId: string | undefined
|
||||||
let accountId: string | undefined
|
|
||||||
let accountAcct: string | undefined
|
let accountAcct: string | undefined
|
||||||
|
|
||||||
const segments = parsed.pathname.split('/')
|
const segments = parsed.pathname.split('/')
|
||||||
const last = segments[segments.length - 1]
|
const last = segments[segments.length - 1]
|
||||||
const length = segments.length // there is a starting slash
|
const length = segments.length // there is a starting slash
|
||||||
|
|
||||||
|
const testAndAssignStatusId = (id: string) => {
|
||||||
|
if (!!parseInt(id)) {
|
||||||
|
statusId = id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (last?.startsWith('@')) {
|
switch (last?.startsWith('@')) {
|
||||||
case true:
|
case true:
|
||||||
if (length === 2 || (length === 3 && segments[length - 2] === 'web')) {
|
if (length === 2 || (length === 3 && segments[length - 2] === 'web')) {
|
||||||
|
@ -45,14 +50,14 @@ export const urlMatcher = (
|
||||||
if (nextToLast === 'statuses') {
|
if (nextToLast === 'statuses') {
|
||||||
if (length === 4 && segments[length - 3] === 'web') {
|
if (length === 4 && segments[length - 3] === 'web') {
|
||||||
// https://social.xmflsct.com/web/statuses/105590085754428765 <- old
|
// https://social.xmflsct.com/web/statuses/105590085754428765 <- old
|
||||||
statusId = last
|
testAndAssignStatusId(last)
|
||||||
} else if (
|
} else if (
|
||||||
length === 5 &&
|
length === 5 &&
|
||||||
segments[length - 2] === 'statuses' &&
|
segments[length - 2] === 'statuses' &&
|
||||||
segments[length - 4] === 'users'
|
segments[length - 4] === 'users'
|
||||||
) {
|
) {
|
||||||
// https://social.xmflsct.com/users/tooot/statuses/105590085754428765 <- default Mastodon
|
// https://social.xmflsct.com/users/tooot/statuses/105590085754428765 <- default Mastodon
|
||||||
statusId = last
|
testAndAssignStatusId(last)
|
||||||
// accountAcct = `@${segments[length - 3]}@${domain}`
|
// accountAcct = `@${segments[length - 3]}@${domain}`
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
|
@ -61,7 +66,7 @@ export const urlMatcher = (
|
||||||
) {
|
) {
|
||||||
// https://social.xmflsct.com/web/@tooot/105590085754428765 <- pretty Mastodon v3.5 and below
|
// https://social.xmflsct.com/web/@tooot/105590085754428765 <- pretty Mastodon v3.5 and below
|
||||||
// https://social.xmflsct.com/@tooot/105590085754428765 <- pretty Mastodon v4.0 and above
|
// https://social.xmflsct.com/@tooot/105590085754428765 <- pretty Mastodon v4.0 and above
|
||||||
statusId = last
|
testAndAssignStatusId(last)
|
||||||
// accountAcct = `${nextToLast}@${domain}`
|
// accountAcct = `${nextToLast}@${domain}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,7 +75,7 @@ export const urlMatcher = (
|
||||||
|
|
||||||
return {
|
return {
|
||||||
domain,
|
domain,
|
||||||
...((accountId || accountAcct) && { account: { id: accountId, acct: accountAcct, _remote } }),
|
...(accountAcct && { account: { acct: accountAcct, _remote } }),
|
||||||
...(statusId && { status: { id: statusId, _remote } })
|
...(statusId && { status: { id: statusId, _remote } })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ const accountQueryFunction = async ({ queryKey }: QueryFunctionContext<QueryKeyA
|
||||||
const match = urlMatcher(key.url)
|
const match = urlMatcher(key.url)
|
||||||
|
|
||||||
const domain = match?.domain
|
const domain = match?.domain
|
||||||
const id = key.id || match?.account?.id
|
const id = key.id
|
||||||
const acct = key.acct || key.username || match?.account?.acct
|
const acct = key.acct || key.username || match?.account?.acct
|
||||||
|
|
||||||
if (!key._local && domain) {
|
if (!key._local && domain) {
|
||||||
|
|
|
@ -244,6 +244,12 @@ export const setAccount = async (account: string) => {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log('log', 'setAccount', `binding storage of ${account}`)
|
||||||
|
storage.account = temp
|
||||||
|
setGlobalStorage('account.active', account)
|
||||||
|
await queryClient.resetQueries()
|
||||||
|
queryClient.clear()
|
||||||
|
|
||||||
await apiGeneral<Mastodon.Account>({
|
await apiGeneral<Mastodon.Account>({
|
||||||
method: 'get',
|
method: 'get',
|
||||||
domain,
|
domain,
|
||||||
|
@ -254,15 +260,10 @@ export const setAccount = async (account: string) => {
|
||||||
})
|
})
|
||||||
.then(res => res.body)
|
.then(res => res.body)
|
||||||
.then(async a => {
|
.then(async a => {
|
||||||
temp.set('auth.account.acct', a.acct)
|
storage.account?.set('auth.account.acct', a.acct)
|
||||||
temp.set('auth.account.avatar_static', a.avatar_static)
|
storage.account?.set('auth.account.avatar_static', a.avatar_static)
|
||||||
|
|
||||||
log('log', 'setAccount', `binding storage of ${account}`)
|
log('log', 'setAccount', 'update details')
|
||||||
await queryClient.resetQueries()
|
|
||||||
queryClient.clear()
|
|
||||||
|
|
||||||
storage.account = temp
|
|
||||||
setGlobalStorage('account.active', account)
|
|
||||||
})
|
})
|
||||||
.catch(async error => {
|
.catch(async error => {
|
||||||
if (error?.status && error.status == 401) {
|
if (error?.status && error.status == 401) {
|
||||||
|
@ -302,7 +303,7 @@ export const removeAccount = async (account: string, warning: boolean = true) =>
|
||||||
apiGeneral({
|
apiGeneral({
|
||||||
method: 'post',
|
method: 'post',
|
||||||
domain: revokeDetails.domain,
|
domain: revokeDetails.domain,
|
||||||
url: '/oauth/revoke',
|
url: 'oauth/revoke',
|
||||||
body: revokeDetails
|
body: revokeDetails
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,3 +4,7 @@ import { MMKV } from 'react-native-mmkv'
|
||||||
export const storage: { global: MMKV; account?: MMKV } = { global: new MMKV(), account: undefined }
|
export const storage: { global: MMKV; account?: MMKV } = { global: new MMKV(), account: undefined }
|
||||||
|
|
||||||
export const secureStorage = createSecureStore()
|
export const secureStorage = createSecureStore()
|
||||||
|
|
||||||
|
export const GLOBAL: { connect?: boolean } = {
|
||||||
|
connect: undefined
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue