mirror of
https://github.com/streetwriters/notesnook.git
synced 2025-12-23 23:19:40 +01:00
upgrade navigation
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import NetInfo from '@react-native-community/netinfo';
|
||||
import {EV, EVENTS} from 'notes-core/common';
|
||||
import React, {useEffect} from 'react';
|
||||
import {Appearance, AppState, Linking, Platform} from 'react-native';
|
||||
import {Appearance, AppState, Keyboard, Linking, Platform} from 'react-native';
|
||||
import RNExitApp from 'react-native-exit-app';
|
||||
import * as RNIap from 'react-native-iap';
|
||||
import {enabled} from 'react-native-privacy-snapshot';
|
||||
@@ -143,6 +143,9 @@ export const AppRootEvents = React.memo(
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
|
||||
|
||||
const onSessionExpired = async () => {
|
||||
await Storage.write('loginSessionHasExpired', 'expired');
|
||||
eSendEvent(eOpenLoginDialog, 4);
|
||||
@@ -280,7 +283,7 @@ export const AppRootEvents = React.memo(
|
||||
ToastEvent.show({
|
||||
heading: 'Sync failed',
|
||||
message: e.message,
|
||||
context: context,
|
||||
context: "global",
|
||||
});
|
||||
} finally {
|
||||
dispatch({type: Actions.SYNCING, syncing: false});
|
||||
|
||||
@@ -2,7 +2,7 @@ import 'react-native-gesture-handler';
|
||||
import React from 'react';
|
||||
import {AppRegistry} from 'react-native';
|
||||
import {name as appName} from './app.json';
|
||||
import { enableScreens } from 'react-native-screens';
|
||||
import {enableScreens} from 'react-native-screens';
|
||||
global.Buffer = require('buffer').Buffer;
|
||||
enableScreens(true);
|
||||
let Provider;
|
||||
@@ -10,8 +10,8 @@ let App;
|
||||
let NotesnookShare;
|
||||
|
||||
const AppProvider = () => {
|
||||
Provider = require('./src/provider').Provider
|
||||
App = require("./App").default
|
||||
Provider = require('./src/provider').Provider;
|
||||
App = require('./App').default;
|
||||
return (
|
||||
<Provider>
|
||||
<App />
|
||||
@@ -21,6 +21,6 @@ const AppProvider = () => {
|
||||
|
||||
AppRegistry.registerComponent(appName, () => AppProvider);
|
||||
AppRegistry.registerComponent('NotesnookShare', () => {
|
||||
NotesnookShare = require("./NotesnookShare").default
|
||||
NotesnookShare = require('./NotesnookShare').default;
|
||||
return NotesnookShare;
|
||||
})
|
||||
});
|
||||
|
||||
@@ -2,26 +2,15 @@ import {
|
||||
activateKeepAwake,
|
||||
deactivateKeepAwake,
|
||||
} from '@sayem314/react-native-keep-awake';
|
||||
import React, {
|
||||
createRef,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react';
|
||||
import {Component} from 'react';
|
||||
import {FlatList} from 'react-native';
|
||||
import {Dimensions, View} from 'react-native';
|
||||
import React, {Component, createRef, useEffect, useRef, useState} from 'react';
|
||||
import {Dimensions, FlatList, Keyboard, TextInput, View} from 'react-native';
|
||||
import Animated, {useValue} from 'react-native-reanimated';
|
||||
import ScrollableTabView from 'react-native-scrollable-tab-view';
|
||||
import {notesnook} from './e2e/test.ids';
|
||||
import ContextMenu from './src/components/ContextMenu';
|
||||
import {DialogManager} from './src/components/DialogManager';
|
||||
import {DummyText} from './src/components/DummyText';
|
||||
import {Menu} from './src/components/Menu';
|
||||
import Splash from './src/components/SplashScreen';
|
||||
import {Toast} from './src/components/Toast';
|
||||
import {NavigationStack} from './src/navigation/Drawer';
|
||||
import {NavigatorStack} from './src/navigation/NavigatorStack';
|
||||
import {useTracked} from './src/provider';
|
||||
import {Actions} from './src/provider/Actions';
|
||||
@@ -31,7 +20,7 @@ import {
|
||||
eSubscribeEvent,
|
||||
eUnSubscribeEvent,
|
||||
} from './src/services/EventManager';
|
||||
import {editing, setWidthHeight} from './src/utils';
|
||||
import {dHeight, editing, setWidthHeight} from './src/utils';
|
||||
import {updateStatusBarColor} from './src/utils/Colors';
|
||||
import {
|
||||
eClearEditor,
|
||||
@@ -51,17 +40,21 @@ let layoutTimer = null;
|
||||
let currentTab = 0;
|
||||
|
||||
const onChangeTab = async obj => {
|
||||
console.log(obj.i);
|
||||
if (obj.i === 1) {
|
||||
console.log('making note');
|
||||
eSendEvent(eCloseSideMenu);
|
||||
editing.movedAway = false;
|
||||
currentTab = 1;
|
||||
activateKeepAwake();
|
||||
eSendEvent('navigate');
|
||||
eSendEvent(eClearEditor, 'addHandler');
|
||||
console.log(editing.currentlyEditing, getNote(), editing.isRestoringState);
|
||||
if (
|
||||
!editing.isRestoringState &&
|
||||
(!editing.currentlyEditing || !getNote())
|
||||
) {
|
||||
console.log('new note');
|
||||
eSendEvent(eOnLoadNote, {type: 'new'});
|
||||
editing.currentlyEditing = true;
|
||||
}
|
||||
@@ -156,8 +149,8 @@ const AppStack = React.memo(
|
||||
const {colors, deviceMode} = state;
|
||||
const [dimensions, setDimensions] = useState({width, height});
|
||||
const animatedOpacity = useValue(0);
|
||||
const animatedZIndex = useValue(-10);
|
||||
|
||||
const animatedHeight = useValue(0);
|
||||
const overlayRef = useRef();
|
||||
const showFullScreenEditor = () => {
|
||||
dispatch({type: Actions.FULLSCREEN, state: true});
|
||||
editorRef.current?.setNativeProps({
|
||||
@@ -184,6 +177,7 @@ const AppStack = React.memo(
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
toggleView(false);
|
||||
eSubscribeEvent(eOpenFullscreenEditor, showFullScreenEditor);
|
||||
eSubscribeEvent(eCloseFullscreenEditor, closeFullScreenEditor);
|
||||
|
||||
@@ -225,13 +219,16 @@ const AppStack = React.memo(
|
||||
if (DDS.isLargeTablet()) {
|
||||
//console.log('setting large tab');
|
||||
setDeviceMode('tablet', size);
|
||||
tabBarRef.current?.goToIndex(0)
|
||||
sleep(300).then(r => eSendEvent(eOpenSideMenu));
|
||||
} else if (DDS.isSmallTab) {
|
||||
//console.log('setting small tab');
|
||||
setDeviceMode('smallTablet', size);
|
||||
tabBarRef.current?.goToIndex(0)
|
||||
sleep(300).then(r => eSendEvent(eOpenSideMenu));
|
||||
} else {
|
||||
setDeviceMode('mobile', size);
|
||||
tabBarRef.current?.goToIndex(1)
|
||||
sleep(300).then(r => eSendEvent(eOpenSideMenu));
|
||||
}
|
||||
}
|
||||
@@ -254,19 +251,30 @@ const AppStack = React.memo(
|
||||
}
|
||||
}
|
||||
|
||||
const onScroll = scroll => {
|
||||
currentScroll = scroll;
|
||||
if (scroll === 0) {
|
||||
eSendEvent(eOpenSideMenu);
|
||||
const onScroll = scrollOffset => {
|
||||
if (scrollOffset > 299) {
|
||||
animatedOpacity.setValue(0);
|
||||
toggleView(false);
|
||||
} else {
|
||||
eSendEvent(eCloseSideMenu);
|
||||
let o = scrollOffset / 300;
|
||||
let op = 0;
|
||||
if (o < 0) {
|
||||
op = 1;
|
||||
} else {
|
||||
op = 1 - o;
|
||||
}
|
||||
animatedOpacity.setValue(op);
|
||||
toggleView(true);
|
||||
}
|
||||
};
|
||||
|
||||
const renderTabBar = useCallback(() => <></>, []);
|
||||
|
||||
const toggleView = show => {
|
||||
//animatedZIndex.setValue(show? 999 : -10)
|
||||
overlayRef.current?.setNativeProps({
|
||||
style: {
|
||||
display: show ? 'flex' : 'none',
|
||||
zIndex: show ? 999 : -10,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -277,11 +285,7 @@ const AppStack = React.memo(
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
backgroundColor: colors.bg,
|
||||
}}
|
||||
//onMoveShouldSetResponderCapture={_moveResponder}
|
||||
// onTouchEnd={_onTouchEnd}
|
||||
//onStartShouldSetResponderCapture={_responder}
|
||||
>
|
||||
}}>
|
||||
{deviceMode && (
|
||||
<CustomTabs
|
||||
ref={tabBarRef}
|
||||
@@ -289,65 +293,68 @@ const AppStack = React.memo(
|
||||
zIndex: 1,
|
||||
}}
|
||||
onDrawerStateChange={state => {
|
||||
console.log(state);
|
||||
//console.log(state);
|
||||
}}
|
||||
initialIndex={deviceMode === 'smallTablet' ? 0 : 1}
|
||||
offsets={{
|
||||
a: 300,
|
||||
b: dimensions.width + 300,
|
||||
c: dimensions.width * 2 + 300,
|
||||
a: deviceMode === 'smallTablet' ? dimensions.width : 300,
|
||||
b:
|
||||
deviceMode === 'smallTablet'
|
||||
? dimensions.width
|
||||
: dimensions.width + 300,
|
||||
c:
|
||||
deviceMode === 'smallTablet'
|
||||
? dimensions.width * 2
|
||||
: dimensions.width * 2 + 300,
|
||||
}}
|
||||
items={[
|
||||
<View
|
||||
style={{
|
||||
height: '100%',
|
||||
width: 300,
|
||||
width:
|
||||
deviceMode === 'smallTablet'
|
||||
? dimensions.width * 0.35
|
||||
: 300,
|
||||
}}>
|
||||
<Menu />
|
||||
</View>,
|
||||
<View
|
||||
style={{
|
||||
height: '100%',
|
||||
width: dimensions.width,
|
||||
width:
|
||||
deviceMode === 'mobile'
|
||||
? dimensions.width
|
||||
: dimensions.width * 0.65,
|
||||
}}>
|
||||
<Animated.View
|
||||
onTouchEnd={() => {
|
||||
tabBarRef.current?.listRef?.current?.scrollToIndex({
|
||||
animated: true,
|
||||
index: 1,
|
||||
viewOffset: 0,
|
||||
viewPosition: 0,
|
||||
});
|
||||
}}
|
||||
{deviceMode === 'mobile' && (
|
||||
<View
|
||||
style={{
|
||||
position: 'absolute',
|
||||
width: dimensions.width,
|
||||
backgroundColor: 'rgba(0,0,0,0.2)',
|
||||
opacity: animatedOpacity,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
display: 'none',
|
||||
zIndex: -10,
|
||||
}}
|
||||
ref={overlayRef}>
|
||||
<Animated.View
|
||||
onTouchEnd={() => {
|
||||
tabBarRef.current?.goToIndex(1)
|
||||
}}
|
||||
style={{
|
||||
backgroundColor: 'rgba(0,0,0,0.2)',
|
||||
opacity: animatedOpacity,
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<NavigatorStack />
|
||||
</View>,
|
||||
<EditorWrapper dimensions={dimensions} />,
|
||||
]}
|
||||
onScroll={scrollOffset => {
|
||||
if (scrollOffset > 300) {
|
||||
animatedOpacity.setValue(0);
|
||||
toggleView(false);
|
||||
|
||||
} else {
|
||||
let o = scrollOffset / 300;
|
||||
let op = 0;
|
||||
if (o < 0) {
|
||||
op = 1;
|
||||
} else {
|
||||
op = 1 - o;
|
||||
}
|
||||
animatedOpacity.setValue(op);
|
||||
toggleView(true)
|
||||
}
|
||||
}}
|
||||
onScroll={onScroll}
|
||||
onChangeTab={onChangeTab}
|
||||
/>
|
||||
)}
|
||||
@@ -428,70 +435,92 @@ const AppStack = React.memo(
|
||||
() => true,
|
||||
);
|
||||
|
||||
let OFFSET_A = 300;
|
||||
let OFFSET_B = 300 + Dimensions.get('window').width;
|
||||
let OFFSET_C = 300 + Dimensions.get('window').width * 2;
|
||||
|
||||
class CustomTabs extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.listRef = createRef();
|
||||
this.scrollOffset = 300;
|
||||
this.scrollOffset = props.initialIndex === 0 ? 0 : 300;
|
||||
this.page = 0;
|
||||
this.currentDrawerState = false;
|
||||
this.inputElement = createRef();
|
||||
this.keyboardState = false;
|
||||
this.scrollTimeout = null;
|
||||
this.scrollEnabled = true;
|
||||
this.responderAllowedScroll = false;
|
||||
}
|
||||
|
||||
|
||||
renderItem = ({item, index}) => this.props.items[index];
|
||||
|
||||
onMoveShouldSetResponder = event => {
|
||||
let x = event.nativeEvent.locationX;
|
||||
let y = event.nativeEvent.locationY;
|
||||
// console.log(this.responderAllowedScroll,'allowed scrolling')
|
||||
if (this.responderAllowedScroll) return;
|
||||
let x = event.nativeEvent.pageX;
|
||||
let y = event.nativeEvent.pageY;
|
||||
this.hideKeyboardIfVisible();
|
||||
let cOffset = this.scrollOffset.toFixed(0);
|
||||
let pOffset = this.props.offsets.b.toFixed(0);
|
||||
let heightCheck = !editing.tooltip
|
||||
? updatedDimensions.height - 70
|
||||
: updatedDimensions.height - 140;
|
||||
|
||||
if (this.scrollOffset.toFixed(0) === this.props.offsets.b.toFixed(0)) {
|
||||
if (x > 50 && y < Dimensions.get('window').height - 70) {
|
||||
this.listRef.current?.getNativeScrollRef().setNativeProps({
|
||||
scrollEnabled: false,
|
||||
});
|
||||
this.listRef.current?.scrollToIndex({
|
||||
animated: true,
|
||||
index: 2,
|
||||
viewOffset: 0,
|
||||
viewPosition: 0,
|
||||
});
|
||||
if (cOffset > pOffset - 50) {
|
||||
if (x > 50 || y > heightCheck) {
|
||||
this.responderAllowedScroll = false;
|
||||
this.setScrollEnabled(false);
|
||||
return;
|
||||
} else {
|
||||
this.listRef.current?.getNativeScrollRef().setNativeProps({
|
||||
scrollEnabled: true,
|
||||
});
|
||||
this.responderAllowedScroll = true;
|
||||
this.setScrollEnabled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.responderAllowedScroll = true;
|
||||
};
|
||||
|
||||
openDrawer = () => {
|
||||
console.log('open');
|
||||
if (this.page === 0) {
|
||||
this.listRef.current?.scrollToIndex({
|
||||
animated: true,
|
||||
index: 0,
|
||||
viewOffset: 0,
|
||||
viewPosition: 0,
|
||||
});
|
||||
this.goToIndex(0);
|
||||
}
|
||||
};
|
||||
|
||||
closeDrawer = () => {
|
||||
console.log('close');
|
||||
if (this.page === 0) {
|
||||
this.goToIndex(1);
|
||||
}
|
||||
};
|
||||
|
||||
hideKeyboardIfVisible() {
|
||||
if ((editing.keyboardState || editing.isFocused) && this.scrollOffset < this.props.offsets.b - 50) {
|
||||
editing.isFocused = false;
|
||||
editing.keyboardState = false;
|
||||
this.inputElement.current?.focus();
|
||||
this.inputElement.current?.blur();
|
||||
}
|
||||
}
|
||||
|
||||
goToIndex(index, animated = true) {
|
||||
// console.log('called me', index);
|
||||
this.listRef.current?.scrollToIndex({
|
||||
animated: true,
|
||||
index: 1,
|
||||
animated: animated,
|
||||
index: index,
|
||||
viewOffset: 0,
|
||||
viewPosition: 0,
|
||||
});
|
||||
}
|
||||
|
||||
setScrollEnabled = enabled => {
|
||||
this.scrollEnabled = enabled;
|
||||
this.listRef.current?.getNativeScrollRef().setNativeProps({
|
||||
scrollEnabled: enabled,
|
||||
});
|
||||
};
|
||||
|
||||
setScrollEnabled = () => {};
|
||||
|
||||
onTouchEnd = () => {
|
||||
//console.log('touch has ended');
|
||||
this.responderAllowedScroll = false;
|
||||
this.listRef.current?.getNativeScrollRef().setNativeProps({
|
||||
scrollEnabled: true,
|
||||
});
|
||||
@@ -499,46 +528,76 @@ class CustomTabs extends Component {
|
||||
|
||||
onScroll = event => {
|
||||
this.scrollOffset = event.nativeEvent.contentOffset.x;
|
||||
if (this.page === 1) {
|
||||
this.hideKeyboardIfVisible();
|
||||
}
|
||||
this.props.onScroll(this.scrollOffset);
|
||||
if (this.scrollTimeout) {
|
||||
clearTimeout(this.scrollTimeout);
|
||||
this.scrollTimeout = null;
|
||||
}
|
||||
this.scrollTimeout = setTimeout(() => {
|
||||
if (
|
||||
this.scrollOffset !== this.props.offsets.a &&
|
||||
this.page === 1 &&
|
||||
!this.scrollEnabled
|
||||
) {
|
||||
this.goToIndex(2, false);
|
||||
}
|
||||
}, 300);
|
||||
};
|
||||
|
||||
goToPage = page => {
|
||||
if (page === 0) {
|
||||
this.listRef.current?.scrollToIndex({
|
||||
animated: true,
|
||||
index: 1,
|
||||
viewOffset: 0,
|
||||
viewPosition: 0,
|
||||
});
|
||||
this.scrollOffset = this.props.offsets.a;
|
||||
this.hideKeyboardIfVisible();
|
||||
this.goToIndex(1);
|
||||
} else if (page === 1) {
|
||||
this.listRef.current?.scrollToIndex({
|
||||
animated: true,
|
||||
index: 2,
|
||||
viewOffset: 0,
|
||||
viewPosition: 0,
|
||||
});
|
||||
this.goToIndex(2);
|
||||
}
|
||||
if (this.page !== page) {
|
||||
this.props.onChangeTab({i: page, from: this.page});
|
||||
this.page = page;
|
||||
}
|
||||
};
|
||||
|
||||
keyExtractor = (item, index) => item;
|
||||
|
||||
onScrollEnd = event => {
|
||||
this.page = 0;
|
||||
if (this.scrollOffset.toFixed(0) === this.props.offsets.b.toFixed(0)) {
|
||||
this.page = 1;
|
||||
//console.log('scroll end');
|
||||
this.responderAllowedScroll = false;
|
||||
let page = 0;
|
||||
if (this.scrollOffset > this.props.offsets.b - 50) {
|
||||
page = 1;
|
||||
} else {
|
||||
this.hideKeyboardIfVisible();
|
||||
}
|
||||
let drawerState = page === 0 && this.scrollOffset < 10;
|
||||
if (drawerState !== this.currentDrawerState) {
|
||||
this.currentDrawerState = drawerState;
|
||||
this.props.onDrawerStateChange(this.currentDrawerState);
|
||||
}
|
||||
if (this.page !== page) {
|
||||
console.log(page);
|
||||
this.props.onChangeTab({i: page, from: this.page});
|
||||
this.page = page;
|
||||
}
|
||||
this.props.onDrawerStateChange(this.page === 0 && this.scrollOffset < 10);
|
||||
this.props.onChangeTab(this.page);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View
|
||||
onTouchEnd={this.onTouchEnd}
|
||||
onMoveShouldSetResponder={this.props.onMoveShouldSetResponder}
|
||||
onMoveShouldSetResponderCapture={this.onMoveShouldSetResponder}
|
||||
onStartShouldSetResponderCapture={this.onMoveShouldSetResponder}
|
||||
style={{
|
||||
flex: 1,
|
||||
}}>
|
||||
<TextInput
|
||||
ref={this.inputElement}
|
||||
style={{height: 1, padding: 0, width: 1, position: 'absolute'}}
|
||||
blurOnSubmit={false}
|
||||
/>
|
||||
<FlatList
|
||||
ref={this.listRef}
|
||||
horizontal
|
||||
@@ -551,11 +610,14 @@ class CustomTabs extends Component {
|
||||
initialNumToRender={100}
|
||||
alwaysBounceHorizontal={false}
|
||||
scrollToOverflowEnabled={false}
|
||||
scrollsToTop={false}
|
||||
scrollEventThrottle={1}
|
||||
directionalLockEnabled
|
||||
maintainVisibleContentPosition={true}
|
||||
overScrollMode="never"
|
||||
decelerationRate="fast"
|
||||
maxToRenderPerBatch={100}
|
||||
removeClippedSubviews={false}
|
||||
keyboardDismissMode="on-drag"
|
||||
keyboardDismissMode="none"
|
||||
keyboardShouldPersistTaps="always"
|
||||
showsHorizontalScrollIndicator={false}
|
||||
disableIntervalMomentum={true}
|
||||
@@ -564,7 +626,7 @@ class CustomTabs extends Component {
|
||||
this.props.offsets.b,
|
||||
this.props.offsets.c,
|
||||
]}
|
||||
initialScrollIndex={1}
|
||||
initialScrollIndex={this.props.initialIndex}
|
||||
data={['drawer', 'navigation', 'editor']}
|
||||
renderItem={this.renderItem}
|
||||
/>
|
||||
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
import Share from 'react-native-share';
|
||||
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import { notesnook } from '../../../e2e/test.ids';
|
||||
import { useTracked } from '../../provider';
|
||||
import { useNoteStore, useTracked, useTrackedNotes } from '../../provider';
|
||||
import { Actions } from '../../provider/Actions';
|
||||
import { DDS } from '../../services/DeviceDetection';
|
||||
import {
|
||||
@@ -59,6 +59,7 @@ export const ActionSheetComponent = ({
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const [isPinnedToMenu, setIsPinnedToMenu] = useState(false);
|
||||
const [note, setNote] = useState(item);
|
||||
|
||||
const [noteInTopic, setNoteInTopic] = useState(
|
||||
editing.actionAfterFirstSave.type === 'topic' &&
|
||||
db.notebooks
|
||||
@@ -345,7 +346,11 @@ export const ActionSheetComponent = ({
|
||||
} else {
|
||||
await db.notebooks.notebook(note.id).favorite();
|
||||
}
|
||||
dispatch({type: Actions.FAVORITES});
|
||||
//dispatch({type: Actions.NOTES});
|
||||
dispatchh({type:Actions.NOTES});
|
||||
//setNotes()
|
||||
//eSendEvent("onListUpdate",db.notes.note(note.id).data);
|
||||
return;
|
||||
Navigation.setRoutesToUpdate([
|
||||
Navigation.routeNames.NotesPage,
|
||||
Navigation.routeNames.Favorites,
|
||||
|
||||
@@ -6,7 +6,7 @@ import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||
import {notesnook} from '../../../e2e/test.ids';
|
||||
import {useTracked} from '../../provider';
|
||||
import {DDS} from '../../services/DeviceDetection';
|
||||
import {getElevation, showContext, showTooltip, TOOLTIP_POSITIONS} from '../../utils';
|
||||
import {editing, getElevation, showContext, showTooltip, TOOLTIP_POSITIONS} from '../../utils';
|
||||
import {normalize, SIZE} from '../../utils/SizeUtils';
|
||||
import {PressableButton} from '../PressableButton';
|
||||
import RNTooltips from 'react-native-tooltips';
|
||||
@@ -29,11 +29,15 @@ export const ContainerBottomButton = ({
|
||||
}
|
||||
|
||||
const onKeyboardHide = async () => {
|
||||
console.log('called hide')
|
||||
editing.keyboardState = false;
|
||||
if (DDS.isTab) return;
|
||||
animate(0);
|
||||
};
|
||||
|
||||
const onKeyboardShow = async () => {
|
||||
console.log('called show');
|
||||
editing.keyboardState = true;
|
||||
if (DDS.isTab) return;
|
||||
animate(150);
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ import Seperator from '../../components/Seperator';
|
||||
import {useTracked} from '../../provider';
|
||||
import {DDS} from '../../services/DeviceDetection';
|
||||
import {eSubscribeEvent, eUnSubscribeEvent} from '../../services/EventManager';
|
||||
import {getElevation, } from '../../utils';
|
||||
import {getElevation} from '../../utils';
|
||||
import {
|
||||
eCloseJumpToDialog,
|
||||
eOpenJumpToDialog,
|
||||
@@ -26,7 +26,7 @@ const JumpToDialog = ({scrollRef}) => {
|
||||
const onPress = (item, index) => {
|
||||
let offset = 35 * index;
|
||||
let ind = notes.findIndex(
|
||||
(i) => i.title === item.title && i.type === 'header',
|
||||
i => i.title === item.title && i.type === 'header',
|
||||
);
|
||||
ind = ind + 1;
|
||||
ind = ind - (index + 1);
|
||||
@@ -47,7 +47,7 @@ const JumpToDialog = ({scrollRef}) => {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onScroll = (y) => {
|
||||
const onScroll = y => {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
timeout = null;
|
||||
@@ -72,11 +72,11 @@ const JumpToDialog = ({scrollRef}) => {
|
||||
|
||||
const loadOffsets = () => {
|
||||
notes
|
||||
.filter((i) => i.type === 'header')
|
||||
.filter(i => i.type === 'header')
|
||||
.map((item, index) => {
|
||||
let offset = 35 * index;
|
||||
let ind = notes.findIndex(
|
||||
(i) => i.title === item.title && i.type === 'header',
|
||||
i => i.title === item.title && i.type === 'header',
|
||||
);
|
||||
ind = ind + 1;
|
||||
ind = ind - (index + 1);
|
||||
@@ -129,9 +129,9 @@ const JumpToDialog = ({scrollRef}) => {
|
||||
key="go to top"
|
||||
onPress={() => {
|
||||
scrollRef.current?.scrollToOffset(0, 0, true);
|
||||
close()
|
||||
close();
|
||||
}}
|
||||
type='shade'
|
||||
type="shade"
|
||||
customStyle={{
|
||||
minWidth: '20%',
|
||||
maxWidth: '46%',
|
||||
@@ -151,7 +151,7 @@ const JumpToDialog = ({scrollRef}) => {
|
||||
</Heading>
|
||||
</PressableButton>
|
||||
{notes
|
||||
.filter((i) => i.type === 'header')
|
||||
.filter(i => i.type === 'header')
|
||||
.map((item, index) => {
|
||||
return item.title ? (
|
||||
<PressableButton
|
||||
|
||||
@@ -28,6 +28,8 @@ const NoteItem = ({item, isTrash}) => {
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<View
|
||||
@@ -54,15 +56,12 @@ const NoteItem = ({item, isTrash}) => {
|
||||
</Heading>
|
||||
) : null}
|
||||
|
||||
<Text
|
||||
<Heading
|
||||
numberOfLines={1}
|
||||
style={{
|
||||
color: COLORS_NOTE[item.color] || colors.heading,
|
||||
fontSize: SIZE.md,
|
||||
fontWeight: 'bold',
|
||||
}}>
|
||||
{item.title + ' '}
|
||||
</Text>
|
||||
color={COLORS_NOTE[item.color] || colors.heading}
|
||||
size={SIZE.md}>
|
||||
{item.title}
|
||||
</Heading>
|
||||
|
||||
{item.headline ? (
|
||||
<Paragraph numberOfLines={2}>{item.headline}</Paragraph>
|
||||
|
||||
@@ -1,25 +1,20 @@
|
||||
import React, {useEffect, useState} from 'react';
|
||||
import {Linking} from 'react-native';
|
||||
import {Platform} from 'react-native';
|
||||
import {View} from 'react-native';
|
||||
import {useSafeAreaInsets} from 'react-native-safe-area-context';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Linking, Platform, View } from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import BaseDialog from '../../components/Dialog/base-dialog';
|
||||
import {useTracked} from '../../provider';
|
||||
import {DDS} from '../../services/DeviceDetection';
|
||||
import {eSubscribeEvent, eUnSubscribeEvent} from '../../services/EventManager';
|
||||
import {getElevation} from '../../utils';
|
||||
import {eCloseRateDialog, eOpenRateDialog} from '../../utils/Events';
|
||||
import {MMKV} from '../../utils/mmkv';
|
||||
import {SIZE} from '../../utils/SizeUtils';
|
||||
import {Button} from '../Button';
|
||||
import DialogButtons from '../Dialog/dialog-buttons';
|
||||
import DialogHeader from '../Dialog/dialog-header';
|
||||
import { useTracked } from '../../provider';
|
||||
import { eSubscribeEvent, eUnSubscribeEvent } from '../../services/EventManager';
|
||||
import { getElevation } from '../../utils';
|
||||
import { eCloseRateDialog, eOpenRateDialog } from '../../utils/Events';
|
||||
import { MMKV } from '../../utils/mmkv';
|
||||
import { SIZE } from '../../utils/SizeUtils';
|
||||
import { Button } from '../Button';
|
||||
import Heading from '../Typography/Heading';
|
||||
import Paragraph from '../Typography/Paragraph';
|
||||
|
||||
const RateDialog = () => {
|
||||
const [state] = useTracked();
|
||||
const {notes, colors, settings} = state;
|
||||
const {colors} = state;
|
||||
const [visible, setVisible] = useState(false);
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React, {useEffect, useRef, useState} from 'react';
|
||||
import {FlatList} from 'react-native';
|
||||
import {RefreshControl, useWindowDimensions} from 'react-native';
|
||||
import {DataProvider, LayoutProvider, RecyclerListView} from 'recyclerlistview';
|
||||
import {useTracked} from '../../provider';
|
||||
import {DDS} from '../../services/DeviceDetection';
|
||||
import {eSendEvent} from '../../services/EventManager';
|
||||
import {eSendEvent, eSubscribeEvent, eUnSubscribeEvent} from '../../services/EventManager';
|
||||
import SettingsService from '../../services/SettingsService';
|
||||
import Sync from '../../services/Sync';
|
||||
import {dHeight, dWidth} from '../../utils';
|
||||
@@ -11,7 +12,9 @@ import {COLORS_NOTE} from '../../utils/Colors';
|
||||
import {eScrollEvent} from '../../utils/Events';
|
||||
import useAnnouncement from '../../utils/useAnnouncement';
|
||||
import JumpToDialog from '../JumpToDialog';
|
||||
import {NotebookItem} from '../NotebookItem';
|
||||
import {NotebookWrapper} from '../NotebookItem/wrapper';
|
||||
import NoteItem from '../NoteItem';
|
||||
import {NoteWrapper} from '../NoteItem/wrapper';
|
||||
import TagItem from '../TagItem';
|
||||
import {Announcement} from './announcement';
|
||||
@@ -31,7 +34,7 @@ const empty_not = {
|
||||
type: 'empty_not_loading',
|
||||
};
|
||||
|
||||
const SimpleList = ({
|
||||
const SimpleList1 = ({
|
||||
listData,
|
||||
type,
|
||||
customRefresh,
|
||||
@@ -63,13 +66,17 @@ const SimpleList = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading) {
|
||||
if (!dataProvider.getDataForIndex(1) || dataProvider.getDataForIndex(1).type.includes("empty")) {
|
||||
if (
|
||||
!dataProvider.getDataForIndex(1) ||
|
||||
dataProvider.getDataForIndex(1).type.includes('empty')
|
||||
) {
|
||||
setDataProvider(
|
||||
dataProvider.cloneWithRows(
|
||||
!listData || listData.length === 0
|
||||
? [header, empty_not]
|
||||
: [header].concat(
|
||||
listData.length > 1 && SettingsService.get().homepage !== screen
|
||||
listData.length > 1 &&
|
||||
SettingsService.get().homepage !== screen
|
||||
? listData.slice(0, 1)
|
||||
: listData,
|
||||
),
|
||||
@@ -77,7 +84,6 @@ const SimpleList = ({
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
if (
|
||||
!listData ||
|
||||
listData.length === 0 ||
|
||||
@@ -101,7 +107,7 @@ const SimpleList = ({
|
||||
if (refreshCallback) {
|
||||
refreshCallback();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const _onScroll = React.useCallback(
|
||||
event => {
|
||||
@@ -223,7 +229,7 @@ const SimpleList = ({
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let scrollProps = React.useMemo(() => {
|
||||
return {
|
||||
@@ -259,7 +265,7 @@ const SimpleList = ({
|
||||
minWidth: 1,
|
||||
};
|
||||
|
||||
const renderFooter = () => (listData.length === 0 ? null : <Footer/>);
|
||||
const renderFooter = () => (listData.length === 0 ? null : <Footer />);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -288,4 +294,208 @@ const SimpleList = ({
|
||||
);
|
||||
};
|
||||
|
||||
const heights = {
|
||||
note: 100,
|
||||
notebook: 110,
|
||||
tag: 80,
|
||||
topic: 80,
|
||||
header: 35,
|
||||
};
|
||||
|
||||
const TrashI = ({item, index}) => {
|
||||
return item.itemType === 'note' ? (
|
||||
<NoteItem item={item} index={index} />
|
||||
) : (
|
||||
<NotebookItem item={item} index={index} />
|
||||
);
|
||||
};
|
||||
|
||||
let renderItems = {
|
||||
notes: NoteWrapper,
|
||||
notebooks: NotebookWrapper,
|
||||
tags: TagItem,
|
||||
section: SectionHeader,
|
||||
trash: TrashI,
|
||||
};
|
||||
|
||||
const SimpleList = ({
|
||||
listData,
|
||||
type,
|
||||
customRefresh,
|
||||
customRefreshing,
|
||||
refreshCallback,
|
||||
sortMenuButton,
|
||||
jumpToDialog,
|
||||
placeholderData,
|
||||
loading,
|
||||
headerProps = {
|
||||
heading: 'Home',
|
||||
},
|
||||
screen,
|
||||
}) => {
|
||||
const [state] = useTracked();
|
||||
const {colors} = state;
|
||||
const [dataProvider, setDataProvider] = useState([]);
|
||||
const scrollRef = useRef();
|
||||
const [announcement, remove] = useAnnouncement();
|
||||
const [_loading,_setLoading] = useState(true);
|
||||
const RenderItem = renderItems[type];
|
||||
const refreshing = false;
|
||||
|
||||
|
||||
const updateList = (item) => {
|
||||
let index = dataProvider.findIndex(i => i.id === item.id);
|
||||
if (index !== -1) {
|
||||
setDataProvider(prev => {
|
||||
prev[index] = item;
|
||||
return prev.slice()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
eSubscribeEvent("onListUpdate",updateList)
|
||||
return () => {
|
||||
eUnSubscribeEvent("onListUpdate",updateList)
|
||||
}
|
||||
},[]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!_loading) {
|
||||
setDataProvider(listData);
|
||||
}
|
||||
},[listData])
|
||||
|
||||
useEffect(() => {
|
||||
if (!loading) {
|
||||
setDataProvider(
|
||||
listData.length > 1 && SettingsService.get().homepage !== screen
|
||||
? listData.slice(0, 1)
|
||||
: listData,
|
||||
);
|
||||
|
||||
if (
|
||||
!listData ||
|
||||
listData.length === 0 ||
|
||||
SettingsService.get().homepage === screen
|
||||
) {
|
||||
setTimeout(() => {
|
||||
_setLoading(false);
|
||||
},1);
|
||||
return;
|
||||
}
|
||||
setTimeout(() => {
|
||||
setDataProvider(listData);
|
||||
_setLoading(false);
|
||||
}, 150);
|
||||
} else {
|
||||
setDataProvider([]);
|
||||
}
|
||||
}, [loading]);
|
||||
|
||||
const renderItem = React.useCallback(
|
||||
({item, index}) =>
|
||||
item.type === 'header' ? (
|
||||
<SectionHeader
|
||||
item={item}
|
||||
index={index}
|
||||
headerProps={headerProps}
|
||||
jumpToDialog={jumpToDialog}
|
||||
sortMenuButton={sortMenuButton}
|
||||
/>
|
||||
) : (
|
||||
<RenderItem item={item} index={index} />
|
||||
),
|
||||
[],
|
||||
);
|
||||
|
||||
const _onRefresh = async () => {
|
||||
await Sync.run();
|
||||
if (refreshCallback) {
|
||||
refreshCallback();
|
||||
}
|
||||
};
|
||||
|
||||
const _onScroll = React.useCallback(
|
||||
event => {
|
||||
if (!event) return;
|
||||
let y = event.nativeEvent.contentOffset.y;
|
||||
eSendEvent(eScrollEvent, {
|
||||
y,
|
||||
screen,
|
||||
});
|
||||
},
|
||||
[screen],
|
||||
);
|
||||
|
||||
let styles = {
|
||||
height: '100%',
|
||||
backgroundColor: colors.bg,
|
||||
width: '100%',
|
||||
minHeight: 1,
|
||||
minWidth: 1,
|
||||
};
|
||||
|
||||
const _keyExtractor = item => item.id || item.title;
|
||||
|
||||
return (
|
||||
<>
|
||||
<FlatList
|
||||
style={styles}
|
||||
keyExtractor={_keyExtractor}
|
||||
ref={scrollRef}
|
||||
data={dataProvider}
|
||||
renderItem={renderItem}
|
||||
onScroll={_onScroll}
|
||||
initialNumToRender={10}
|
||||
maxToRenderPerBatch={10}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
style={{
|
||||
opacity: 0,
|
||||
elevation: 0,
|
||||
}}
|
||||
tintColor={colors.accent}
|
||||
colors={[colors.accent]}
|
||||
progressViewOffset={150}
|
||||
onRefresh={customRefresh ? customRefresh : _onRefresh}
|
||||
refreshing={customRefresh ? customRefreshing : refreshing}
|
||||
/>
|
||||
}
|
||||
ListEmptyComponent={
|
||||
<Empty
|
||||
loading={loading || _loading}
|
||||
placeholderData={placeholderData}
|
||||
headerProps={headerProps}
|
||||
/>
|
||||
}
|
||||
ListFooterComponent={<Footer />}
|
||||
ListHeaderComponent={
|
||||
announcement ? (
|
||||
<Announcement
|
||||
announcement={announcement}
|
||||
remove={remove}
|
||||
color={
|
||||
COLORS_NOTE[headerProps.heading?.toLowerCase()] || colors.accent
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Header
|
||||
title={headerProps.heading}
|
||||
paragraph={headerProps.paragraph}
|
||||
onPress={headerProps.onPress}
|
||||
icon={headerProps.icon}
|
||||
type={type}
|
||||
announcement={announcement}
|
||||
screen={screen}
|
||||
/>
|
||||
)
|
||||
}
|
||||
/>
|
||||
|
||||
<JumpToDialog scrollRef={scrollRef} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SimpleList;
|
||||
|
||||
@@ -34,12 +34,12 @@ export const SectionHeader = ({
|
||||
paddingHorizontal: 12,
|
||||
height: 30 * fontScale,
|
||||
backgroundColor:
|
||||
index === 1
|
||||
index === 0
|
||||
? headerProps.color
|
||||
? colors[headerProps.color]
|
||||
: colors.shade
|
||||
: colors.nav,
|
||||
marginTop: index === 1 ? 0 : 5 * fontScale,
|
||||
marginTop: index === 0 ? 0 : 5 * fontScale,
|
||||
}}>
|
||||
<TouchableWithoutFeedback
|
||||
onPress={() => {
|
||||
@@ -63,7 +63,7 @@ export const SectionHeader = ({
|
||||
{!item.title || item.title === '' ? 'Pinned' : item.title}
|
||||
</Heading>
|
||||
</TouchableWithoutFeedback>
|
||||
{index === 1 && sortMenuButton ? <HeaderMenu /> : null}
|
||||
{index === 0 && sortMenuButton ? <HeaderMenu /> : null}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
@@ -80,7 +80,7 @@ const screenOptionsForAnimation = {
|
||||
export const NavigatorStack = React.memo(
|
||||
() => {
|
||||
const [, dispatch] = useTracked();
|
||||
const [render, setRender] = React.useState(false);
|
||||
const [render, setRender] = React.useState(true);
|
||||
const onStateChange = React.useCallback(() => {
|
||||
if (history.selectionMode) {
|
||||
dispatch({type: Actions.SELECTION_MODE, enabled: false});
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import {Actions} from '../provider/Actions';
|
||||
import {db} from '../utils/DB';
|
||||
import {eOpenLoginDialog, eOpenProgressDialog} from '../utils/Events';
|
||||
import {MMKV} from '../utils/mmkv';
|
||||
import {eSendEvent, ToastEvent} from './EventManager';
|
||||
import { Actions } from '../provider/Actions';
|
||||
import { eOpenLoginDialog } from '../utils/Events';
|
||||
import { eSendEvent } from './EventManager';
|
||||
import PremiumService from './PremiumService';
|
||||
|
||||
export function setLoginMessage(dispatch) {
|
||||
|
||||
@@ -69,6 +69,10 @@ const noteColors = [
|
||||
'#9E9E9E',
|
||||
];
|
||||
|
||||
export const updateList = (items) => {
|
||||
eSendEvent("onListUpdate",items);
|
||||
}
|
||||
|
||||
export function preloadImages(color) {
|
||||
let uri = imgNames.map(name => {
|
||||
return {
|
||||
|
||||
@@ -550,7 +550,7 @@ export async function saveNote(preventUpdate) {
|
||||
|
||||
export async function onWebViewLoad(premium, colors) {
|
||||
if (!checkNote()) {
|
||||
Platform.OS === 'android' ? EditorWebView.current?.requestFocus() : null;
|
||||
//Platform.OS === 'android' ? EditorWebView.current?.requestFocus() : null;
|
||||
}
|
||||
if (premium) {
|
||||
tiny.call(EditorWebView, tiny.setMarkdown, true);
|
||||
@@ -570,6 +570,7 @@ async function restoreEditorState() {
|
||||
appState.note.id &&
|
||||
Date.now() < appState.timestamp + 3600000
|
||||
) {
|
||||
console.log('restoring state');
|
||||
editing.isRestoringState = true;
|
||||
eSendEvent('loadingNote', appState.note);
|
||||
editing.currentlyEditing = true;
|
||||
@@ -581,8 +582,13 @@ async function restoreEditorState() {
|
||||
editing.movedAway = false;
|
||||
eSendEvent('load_overlay', 'hide_editor');
|
||||
editing.isRestoringState = false;
|
||||
return;
|
||||
}
|
||||
editing.isRestoringState = false;
|
||||
return;
|
||||
}
|
||||
editing.isRestoringState = false;
|
||||
|
||||
}
|
||||
|
||||
export let isFromIntent = false;
|
||||
|
||||
@@ -104,6 +104,7 @@ const Editor = React.memo(
|
||||
showsVerticalScrollIndicator={false}
|
||||
scrollEnabled={false}
|
||||
nestedScrollEnabled
|
||||
|
||||
contentContainerStyle={{
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import React, {useCallback, useEffect, useState} from 'react';
|
||||
import {ContainerBottomButton} from '../../components/Container/ContainerBottomButton';
|
||||
import {ContainerTopSection} from '../../components/Container/ContainerTopSection';
|
||||
import {Header} from '../../components/Header/index';
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import { ContainerBottomButton } from '../../components/Container/ContainerBottomButton';
|
||||
import { ContainerTopSection } from '../../components/Container/ContainerTopSection';
|
||||
import { Header } from '../../components/Header/index';
|
||||
import SelectionHeader from '../../components/SelectionHeader';
|
||||
import SimpleList from '../../components/SimpleList';
|
||||
import {useTracked} from '../../provider';
|
||||
import {Actions} from '../../provider/Actions';
|
||||
import {DDS} from '../../services/DeviceDetection';
|
||||
import {eSendEvent} from '../../services/EventManager';
|
||||
import { useTracked } from '../../provider';
|
||||
import { Actions } from '../../provider/Actions';
|
||||
import { DDS } from '../../services/DeviceDetection';
|
||||
import { eSendEvent } from '../../services/EventManager';
|
||||
import Navigation from '../../services/Navigation';
|
||||
import SearchService from '../../services/SearchService';
|
||||
import {InteractionManager, scrollRef} from '../../utils';
|
||||
import {db} from '../../utils/DB';
|
||||
import {eOnLoadNote, eScrollEvent} from '../../utils/Events';
|
||||
import {tabBarRef} from '../../utils/Refs';
|
||||
import { InteractionManager, scrollRef } from '../../utils';
|
||||
import { db } from '../../utils/DB';
|
||||
import { eOnLoadNote, eScrollEvent } from '../../utils/Events';
|
||||
import { tabBarRef } from '../../utils/Refs';
|
||||
|
||||
export const Home = ({navigation}) => {
|
||||
const [state, dispatch] = useTracked();
|
||||
const {loading} = state;
|
||||
const notes = state.notes;
|
||||
const notes = state.notes
|
||||
let ranAfterInteractions = false;
|
||||
|
||||
const onFocus = useCallback(() => {
|
||||
@@ -101,7 +101,7 @@ export const Home = ({navigation}) => {
|
||||
</ContainerTopSection>
|
||||
|
||||
<SimpleList
|
||||
listData={state.notes}
|
||||
listData={state.notes.slice()}
|
||||
scrollRef={scrollRef}
|
||||
type="notes"
|
||||
isHome={true}
|
||||
|
||||
@@ -1,604 +0,0 @@
|
||||
export const delta_data = {
|
||||
type: 'delta',
|
||||
data: [
|
||||
{insert: 'Today, former '},
|
||||
{
|
||||
attributes: {
|
||||
background: 'initial',
|
||||
color: '#663366',
|
||||
link:
|
||||
'https://en.wikipedia.org/wiki/Vice_President_of_the_United_States',
|
||||
},
|
||||
insert: 'Vice President of the United States',
|
||||
},
|
||||
{insert: ' '},
|
||||
{
|
||||
attributes: {
|
||||
background: 'initial',
|
||||
color: '#0b0080',
|
||||
link: 'https://en.wikinews.org/wiki/Joe_Biden',
|
||||
},
|
||||
insert: 'Joe Biden',
|
||||
},
|
||||
{insert: ' was projected by multiple media outlets to have surpassed 270 '},
|
||||
{
|
||||
attributes: {
|
||||
background: 'initial',
|
||||
color: '#663366',
|
||||
link: 'https://en.wikipedia.org/wiki/United_States_Electoral_College',
|
||||
},
|
||||
insert: 'electoral college',
|
||||
},
|
||||
{insert: ' delegate total and therefore become the 46th '},
|
||||
{
|
||||
attributes: {
|
||||
background: 'initial',
|
||||
color: '#0b0080',
|
||||
link: 'https://en.wikinews.org/wiki/President_of_the_United_States',
|
||||
},
|
||||
insert: 'President of the United States',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
' elect.\nHis running mate, Kamala Harris, would become the first female and first African- and Asian-American vice president.\nAt around 11:25am ',
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
background: 'initial',
|
||||
color: '#663366',
|
||||
link:
|
||||
'https://en.wikipedia.org/wiki/Eastern_Standard_Time_(North_America)',
|
||||
},
|
||||
insert: 'US east coast time',
|
||||
},
|
||||
{insert: ' (1625 '},
|
||||
{
|
||||
attributes: {
|
||||
background: 'initial',
|
||||
color: '#663366',
|
||||
link: 'https://en.wikipedia.org/wiki/UTC',
|
||||
},
|
||||
insert: 'UTC',
|
||||
},
|
||||
{insert: '), the '},
|
||||
{
|
||||
attributes: {
|
||||
background: 'initial',
|
||||
color: '#0b0080',
|
||||
link: 'https://en.wikinews.org/wiki/Associated_Press',
|
||||
},
|
||||
insert: 'Associated Press',
|
||||
},
|
||||
{insert: ' (AP) called the election for Biden, as did '},
|
||||
{
|
||||
attributes: {
|
||||
background: 'initial',
|
||||
color: '#0b0080',
|
||||
link: 'https://en.wikinews.org/wiki/NBC_News',
|
||||
},
|
||||
insert: 'NBC News',
|
||||
},
|
||||
{insert: ', when Biden was declared to have won '},
|
||||
{
|
||||
attributes: {
|
||||
background: 'initial',
|
||||
color: '#0b0080',
|
||||
link: 'https://en.wikinews.org/wiki/Pennsylvania',
|
||||
},
|
||||
insert: 'Pennsylvania',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
"'s 20 electoral college votes. Later in the day, the AP and NBC News also called ",
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
background: 'initial',
|
||||
color: '#0b0080',
|
||||
link: 'https://en.wikinews.org/wiki/Nevada',
|
||||
},
|
||||
insert: 'Nevada',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
" for Biden, giving him an additional six electoral college votes, for a total by NBC's reckoning of 279 electoral votes to President ",
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
background: 'initial',
|
||||
color: '#0b0080',
|
||||
link: 'https://en.wikinews.org/wiki/Donald_Trump',
|
||||
},
|
||||
insert: 'Donald Trump',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
"'s 214, or 290 electoral votes by AP's reckoning.\nElectoral college results map when the election was called for Biden.",
|
||||
},
|
||||
{
|
||||
attributes: {height: '128', width: '220'},
|
||||
insert: {
|
||||
image:
|
||||
'https://upload.wikimedia.org/wikinews/en/thumb/3/38/ElectoralCollege2020_with_results_for_Wikinews_11072020.svg/220px-ElectoralCollege2020_with_results_for_Wikinews_11072020.svg.png',
|
||||
},
|
||||
},
|
||||
{attributes: {align: 'center'}, insert: '\n'},
|
||||
{insert: 'Image: '},
|
||||
{
|
||||
attributes: {
|
||||
background: 'initial',
|
||||
color: '#663366',
|
||||
link: 'https://commons.wikimedia.org/wiki/user:Kingofthedead',
|
||||
},
|
||||
insert: 'Kingofthedead',
|
||||
},
|
||||
{insert: '.'},
|
||||
{attributes: {align: 'center'}, insert: '\n'},
|
||||
{
|
||||
insert:
|
||||
'Biden said in a statement, "I am honored and humbled by the trust the American people have placed in me and in Vice President-elect Harris". He added, "With the campaign over, it\'s time to put the anger and the harsh rhetoric behind us and come together as a nation. It\'s time for America to unite. And to heal [...] We are the United States of America. And there\'s nothing we can\'t do, if we do it together."\nPresident Trump has yet to concede, saying earlier in the morning before the call for Biden, "I WON THIS ELECTION, BY A LOT!" on ',
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
background: 'initial',
|
||||
color: '#0b0080',
|
||||
link: 'https://en.wikinews.org/wiki/Twitter',
|
||||
},
|
||||
insert: 'Twitter',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
". Following the announcement of Biden's win, Trump issued a statement at ",
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
background: 'initial',
|
||||
color: '#663366',
|
||||
link:
|
||||
'https://en.wikipedia.org/wiki/Trump_National_Golf_Club_Washington,_D.C.',
|
||||
},
|
||||
insert: 'his golf club',
|
||||
},
|
||||
{insert: ' outside '},
|
||||
{
|
||||
attributes: {
|
||||
background: 'initial',
|
||||
color: '#0b0080',
|
||||
link: 'https://en.wikinews.org/wiki/Washington,_D.C.',
|
||||
},
|
||||
insert: 'Washington, D.C.',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
' saying, "The simple fact is this election is far from over. Joe Biden has not been certified as the winner of any states, let alone any of the highly contested states headed for mandatory recounts, or states where our campaign has valid and legitimate legal challenges that could determine the ultimate victor". The lack of a concession from Trump has no legal standing.\n\nJoseph Robinette Biden Jr. was elected the 46th president of the United States on Saturday, promising to restore political normalcy and a spirit of national unity to confront raging health and economic crises, and making Donald J. Trump a one-term president after four years of tumult in the White House.\nMr. Biden’s victory amounted to a repudiation of Mr. Trump by millions of voters exhausted with his divisive conduct and chaotic administration, and was delivered by an unlikely alliance of women, people of color, old and young voters and a sliver of disaffected Republicans. Mr. Trump is only the third ',
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
color: '#326891',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/11/11/upshot/election-red-blue-economic-divide.html',
|
||||
},
|
||||
insert: 'elected',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
' president since World War II to lose re-election, and the first in more than a quarter-century.\nThe result also provided a history-making moment for Mr. Biden’s running mate, Senator Kamala Harris of California, who will become the first woman to serve as vice president.\nWith his triumph, Mr. Biden, who turns 78 later this month, fulfilled his decades-long ambition in his third bid for the White House, becoming the oldest person elected president. A pillar of Washington who was first elected amid the Watergate scandal, and who prefers political consensus over combat, Mr. Biden will lead a nation and a Democratic Party that have become far more ideological since his arrival in the capital in 1973.\nADVERTISEMENT',
|
||||
},
|
||||
{attributes: {align: 'center'}, insert: '\n'},
|
||||
{
|
||||
attributes: {
|
||||
color: 'black',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/11/07/us/politics/biden-election.html#after-story-ad-1',
|
||||
},
|
||||
insert: 'Continue reading the main story',
|
||||
},
|
||||
{attributes: {align: 'center'}, insert: '\n\n'},
|
||||
{
|
||||
insert:
|
||||
'He offered a mainstream Democratic agenda, yet it was less his policy platform than his biography to which many voters gravitated. Seeking the nation’s highest office a half-century after his first campaign, Mr. Biden — a candidate in the late autumn of his career — presented his life of setback and recovery to voters as a parable for a wounded country.\nAppearing Saturday night before supporters at a drive-in rally in Wilmington, Del., and speaking against the din of enthusiastic honking, Mr. Biden claimed the presidency and called on the country to reunite after what he described as a toxic political interlude.\n',
|
||||
},
|
||||
{attributes: {bold: true}, insert: 'Thanks for reading The Times.'},
|
||||
{attributes: {align: 'center', list: 'bullet'}, insert: '\n'},
|
||||
{
|
||||
attributes: {
|
||||
bold: true,
|
||||
color: '#326891',
|
||||
link: 'https://www.nytimes.com/subscription?campaignId=9L9L9',
|
||||
},
|
||||
insert: 'Subscribe to The Times',
|
||||
},
|
||||
{attributes: {align: 'center'}, insert: '\n'},
|
||||
{
|
||||
insert:
|
||||
'“Let this grim era of demonization in America begin to end here and now,” he said.\nWithout addressing Mr. Trump, the president-elect spoke directly to the president’s supporters and said he recognized their disappointment. “I’ve lost a couple of times myself,” he recalled of his past failures to win the presidency, before adding: “Now let’s give each other a chance.”\nIn a statement earlier in the day, Mr. Trump insisted “this election is far from over” and vowed that his campaign would “start prosecuting our case in court” but offered no details.\nMr. Biden’s victory, which came 48 years to the day after he was first elected to the United States Senate, set off jubilant celebrations in Democratic-leaning cities. In Washington, people streamed into the streets near the White House and cheered as cars bearing American flags drove by honking.\nEditors’ Picks',
|
||||
},
|
||||
{attributes: {header: 2}, insert: '\n'},
|
||||
{
|
||||
attributes: {
|
||||
color: 'black',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/11/08/arts/television/saturday-night-live-dave-chappelle.html?action=click&algo=als_engaged1_desk_filter&block=editors_picks_recirc&fellback=false&imp_id=151568062&impression_id=7263ff30-2713-11eb-ac57-f7fb164a26ff&index=0&pgtype=Article®ion=ccolumn&req_id=989100184&surface=home-featured&action=click&module=editorContent&pgtype=Article®ion=CompanionColumn&contentCollection=Trending',
|
||||
},
|
||||
insert: {
|
||||
image:
|
||||
'https://static01.nyt.com/images/2020/11/09/arts/08snl-dave-chappelle/08snl-dave-chappelle-square640.jpg?quality=75&auto=webp&disable=upscale&width=350',
|
||||
},
|
||||
},
|
||||
{insert: '\n'},
|
||||
{
|
||||
attributes: {
|
||||
color: 'black',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/11/08/arts/television/saturday-night-live-dave-chappelle.html?action=click&algo=als_engaged1_desk_filter&block=editors_picks_recirc&fellback=false&imp_id=151568062&impression_id=7263ff30-2713-11eb-ac57-f7fb164a26ff&index=0&pgtype=Article®ion=ccolumn&req_id=989100184&surface=home-featured&action=click&module=editorContent&pgtype=Article®ion=CompanionColumn&contentCollection=Trending',
|
||||
},
|
||||
insert: '‘Saturday Night Live’ Sends Off Trump With a Ballad',
|
||||
},
|
||||
{attributes: {header: 3}, insert: '\n'},
|
||||
{
|
||||
attributes: {
|
||||
color: 'black',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/11/13/us/murder-hornets-us.html?action=click&algo=als_engaged1_desk_filter&block=editors_picks_recirc&fellback=false&imp_id=183138092&impression_id=7263ff31-2713-11eb-ac57-f7fb164a26ff&index=1&pgtype=Article®ion=ccolumn&req_id=989100184&surface=home-featured&action=click&module=editorContent&pgtype=Article®ion=CompanionColumn&contentCollection=Trending',
|
||||
},
|
||||
insert: {
|
||||
image:
|
||||
'https://static01.nyt.com/images/2020/11/12/multimedia/12xp-murder-hornets-dead/12xp-murder-hornets-dead-square640-v2.jpg?quality=75&auto=webp&disable=upscale&width=350',
|
||||
},
|
||||
},
|
||||
{insert: '\n'},
|
||||
{
|
||||
attributes: {
|
||||
color: 'black',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/11/13/us/murder-hornets-us.html?action=click&algo=als_engaged1_desk_filter&block=editors_picks_recirc&fellback=false&imp_id=183138092&impression_id=7263ff31-2713-11eb-ac57-f7fb164a26ff&index=1&pgtype=Article®ion=ccolumn&req_id=989100184&surface=home-featured&action=click&module=editorContent&pgtype=Article®ion=CompanionColumn&contentCollection=Trending',
|
||||
},
|
||||
insert:
|
||||
'Scientists Destroyed a Nest of Murder Hornets. Here’s What They Learned.',
|
||||
},
|
||||
{attributes: {header: 3}, insert: '\n'},
|
||||
{
|
||||
attributes: {
|
||||
color: 'black',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/11/08/sports/football/nfl-results.html?action=click&algo=als_engaged1_desk_filter&block=editors_picks_recirc&fellback=false&imp_id=588258951&impression_id=7263ff32-2713-11eb-ac57-f7fb164a26ff&index=2&pgtype=Article®ion=ccolumn&req_id=989100184&surface=home-featured&action=click&module=editorContent&pgtype=Article®ion=CompanionColumn&contentCollection=Trending',
|
||||
},
|
||||
insert: {
|
||||
image:
|
||||
'https://static01.nyt.com/images/2020/11/08/sports/08nfl-wwl-top/08nfl-wwl-top-square640-v2.jpg?quality=75&auto=webp&disable=upscale&width=350',
|
||||
},
|
||||
},
|
||||
{insert: '\n'},
|
||||
{
|
||||
attributes: {
|
||||
color: 'black',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/11/08/sports/football/nfl-results.html?action=click&algo=als_engaged1_desk_filter&block=editors_picks_recirc&fellback=false&imp_id=588258951&impression_id=7263ff32-2713-11eb-ac57-f7fb164a26ff&index=2&pgtype=Article®ion=ccolumn&req_id=989100184&surface=home-featured&action=click&module=editorContent&pgtype=Article®ion=CompanionColumn&contentCollection=Trending',
|
||||
},
|
||||
insert: 'What We Learned From Week 9 of the N.F.L. Season',
|
||||
},
|
||||
{attributes: {header: 3}, insert: '\n'},
|
||||
{
|
||||
attributes: {
|
||||
color: 'black',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/11/07/us/politics/biden-election.html?action=click&module=editorContent&pgtype=Article®ion=CompanionColumn&contentCollection=Trending#after-pp_edpick',
|
||||
},
|
||||
insert: 'Continue reading the main story',
|
||||
},
|
||||
{insert: '\n\nADVERTISEMENT'},
|
||||
{attributes: {align: 'center'}, insert: '\n'},
|
||||
{
|
||||
attributes: {
|
||||
color: 'black',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/11/07/us/politics/biden-election.html#after-story-ad-2',
|
||||
},
|
||||
insert: 'Continue reading the main story',
|
||||
},
|
||||
{attributes: {align: 'center'}, insert: '\n\n\n'},
|
||||
{
|
||||
insert:
|
||||
'The race, which concluded after four tense days of vote-counting in a handful of battlegrounds, was a singular referendum on Mr. Trump in a way no president’s re-election has been in modern times. He coveted the attention, and voters who either adored him or loathed him were eager to render judgment on his tenure. From the beginning to the end of the race, Mr. Biden made the president’s character central to his campaign.\nThis unrelenting focus propelled Mr. Biden to victory in historically Democratic strongholds in the industrial Midwest',
|
||||
},
|
||||
{attributes: {italic: true, bold: true}, insert: ' '},
|
||||
{
|
||||
insert:
|
||||
'with Mr. Biden forging a coalition of suburbanites and big-city residents to claim at least three',
|
||||
},
|
||||
{attributes: {bold: true}, insert: ' '},
|
||||
{
|
||||
insert:
|
||||
'states his party lost in 2016. With ballots still being counted in several states, Mr. Biden was leading Mr. Trump in the popular vote by more than four million votes.\nYet even as they turned Mr. Trump out of office, voters sent a more uncertain message about the left-of-center platform Mr. Biden ran on as Democrats lost seats in the House and made only modest gains in the Senate. The divided judgment — a rare example of ticket splitting in partisan times — demonstrated that, for many voters, their disdain for the president was as personal as it was political.\nEven in defeat, though, Mr. Trump demonstrated his enduring appeal to many white voters and his intense popularity in rural areas, underscoring the deep national divisions that Mr. Biden has vowed to heal.\nIn his address Saturday, Mr. Biden saluted Black voters, recalling how they revived his campaign at “its lowest ebb,” back in February, and vowed to honor their loyalty. He said the voters had made clear they wanted both parties “to cooperate in their interest” and said he’d reach out to Republicans and Democrats alike.\n',
|
||||
},
|
||||
{
|
||||
insert: {
|
||||
image:
|
||||
'https://static01.nyt.com/images/2020/11/06/us/politics/06bidenwins-trump/06bidenwins-trump-articleLarge.jpg?quality=75&auto=webp&disable=upscale',
|
||||
},
|
||||
},
|
||||
{insert: '\n\nImage\n\n'},
|
||||
{
|
||||
attributes: {
|
||||
alt:
|
||||
'President Trump was the first incumbent president to lose his re-election bid in more than a quarter-century.',
|
||||
},
|
||||
insert: {
|
||||
image:
|
||||
'https://static01.nyt.com/images/2020/11/06/us/politics/06bidenwins-trump/06bidenwins-trump-articleLarge.jpg?quality=75&auto=webp&disable=upscale',
|
||||
},
|
||||
},
|
||||
{
|
||||
insert:
|
||||
'\n\nPresident Trump was the first incumbent president to lose his re-election bid in more than a quarter-century.',
|
||||
},
|
||||
{attributes: {color: '#888888'}, insert: 'Credit...'},
|
||||
{insert: '\n\n'},
|
||||
{attributes: {color: '#888888'}, insert: 'Doug Mills/The New York Times'},
|
||||
{
|
||||
insert:
|
||||
'\n\nThe outcome of the race came into focus slowly as states and municipalities grappled with the legal and logistical challenges of voting in the midst of the coronavirus pandemic. With an enormous backlog of early and mail-in votes, some states reported their totals in a halting fashion that in the early hours of Wednesday painted a misleadingly rosy picture for Mr. Trump.\nADVERTISEMENT',
|
||||
},
|
||||
{attributes: {align: 'center'}, insert: '\n'},
|
||||
{
|
||||
attributes: {
|
||||
color: 'black',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/11/07/us/politics/biden-election.html#after-story-ad-3',
|
||||
},
|
||||
insert: 'Continue reading the main story',
|
||||
},
|
||||
{attributes: {align: 'center'}, insert: '\n\n\n'},
|
||||
{
|
||||
insert:
|
||||
'But as the big cities of the Midwest and West began to report their totals, the advantage in the race shifted the electoral map in Mr. Biden’s favor. By Wednesday afternoon, the former vice president had rebuilt much of the so-called blue wall in the Midwest, reclaiming the historically Democratic battlegrounds of Wisconsin and Michigan that Mr. Trump carried four years ago. And on Saturday, with troves of ballots coming in from Philadelphia and Pittsburgh, he took back Pennsylvania as well.\nWhile Mr. Biden stopped short of claiming victory as the week unfolded, he appeared several times in his home state, Delaware, to express confidence that he could win, while urging patience as the nation awaited the results. Even as he sought to claim something of an electoral mandate, noting that he had earned more in the popular vote than any other candidate in history, Mr. Biden struck a tone of reconciliation.\nIt would soon be time, he said, “to unite, to heal, to come together as a nation.”\nIn the days after the election, Mr. Biden and his party faced a barrage of attacks from Mr. Trump. The president falsely claimed in a middle-of-the-night appearance at the White House on Wednesday that he had won the race and that Democrats were conjuring fraudulent votes to undermine him, a theme he renewed on Thursday evening in grievance-filled remarks conjuring up, with no evidence, a conspiracy to steal votes from him.\nThe president’s campaign aides adopted a tone of brash defiance as swing states fell to Mr. Biden, promising a flurry of legal action. But while Mr. Trump’s ire had the potential to foment political divisions, there was ',
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
color: '#326891',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/11/06/us/politics/trump-election-voter-fraud.html',
|
||||
},
|
||||
insert: 'no indication that he could succeed',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
' with his seemingly improvisational legal strategy.\nThrough it all, the coronavirus and its ravages on the country hung over the election and shaped the choice for voters. Facing an electorate already fatigued by his aberrant conduct, the president effectively sealed his defeat by minimizing a pandemic that has created simultaneous health and economic crises.\nBeginning with the outbreak of the virus in the country at the start of the year, through his own diagnosis last month and up to the last hours of the election, he ',
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
color: '#326891',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/07/18/us/politics/trump-coronavirus-response-failure-leadership.html',
|
||||
},
|
||||
insert: 'disregarded his medical advisers and public opinion',
|
||||
},
|
||||
{insert: ' even as '},
|
||||
{
|
||||
attributes: {
|
||||
color: '#326891',
|
||||
link:
|
||||
'https://www.nytimes.com/interactive/2020/us/coronavirus-us-cases.html',
|
||||
},
|
||||
insert: 'over 230,000 people',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
' in the United States perished.\nMr. Biden, by contrast, sought to channel the dismay of those appalled by Mr. Trump’s ',
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
color: '#326891',
|
||||
link: 'https://www.nytimes.com/2020/10/02/us/politics/trump-covid.html',
|
||||
},
|
||||
insert: 'mismanagement of the pandemic',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
'. He offered himself as a safe harbor for a broad array of Americans, promising to guide the nation out of what he called the “dark winter” of the outbreak, rather than delivering a visionary message with bright ideological themes.\nADVERTISEMENT',
|
||||
},
|
||||
{attributes: {align: 'center'}, insert: '\n'},
|
||||
{
|
||||
attributes: {
|
||||
color: 'black',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/11/07/us/politics/biden-election.html#after-story-ad-4',
|
||||
},
|
||||
insert: 'Continue reading the main story',
|
||||
},
|
||||
{attributes: {align: 'center'}, insert: '\n\n\n'},
|
||||
{
|
||||
insert:
|
||||
'While the president ridiculed mask-wearing and insisted on continuing his large rallies, ',
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
color: '#326891',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/10/31/us/politics/stanford-study-infections-trump-rallies.html',
|
||||
},
|
||||
insert: 'endangering',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
' his own staff members and supporters, Mr. Biden and Ms. Harris campaigned with caution, avoiding indoor events, insisting on social distancing and always wearing masks.\n',
|
||||
},
|
||||
{
|
||||
insert: {
|
||||
image:
|
||||
'https://static01.nyt.com/images/2020/11/04/us/politics/04bidenwinsHFO-f2/merlin_179504964_10f3acc1-675d-4cfc-9b0c-eed89bbb60ed-articleLarge.jpg?quality=75&auto=webp&disable=upscale',
|
||||
},
|
||||
},
|
||||
{insert: '\n\nImage\n\n'},
|
||||
{
|
||||
attributes: {
|
||||
alt:
|
||||
'Ms. Harris, a senator from California will be the first woman to serve as vice president.',
|
||||
},
|
||||
insert: {
|
||||
image:
|
||||
'https://static01.nyt.com/images/2020/11/04/us/politics/04bidenwinsHFO-f2/merlin_179504964_10f3acc1-675d-4cfc-9b0c-eed89bbb60ed-articleLarge.jpg?quality=75&auto=webp&disable=upscale',
|
||||
},
|
||||
},
|
||||
{
|
||||
insert:
|
||||
'\n\nMs. Harris, a senator from California will be the first woman to serve as vice president.',
|
||||
},
|
||||
{attributes: {color: '#888888'}, insert: 'Credit...'},
|
||||
{insert: '\n\n'},
|
||||
{
|
||||
attributes: {color: '#888888'},
|
||||
insert: 'Michelle V. Agins/The New York Times',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
'\n\nConvinced that he could win back the industrial Northern states that swung to Mr. Trump four years ago, Mr. Biden focused his energy on Michigan, Wisconsin and Pennsylvania. Mr. Biden triumphed in those states on the strength of overwhelming support from women, who voted in large numbers to repudiate Mr. Trump despite his last-minute pleas to “suburban housewives,” as he called them.\nMany of the women who decided the president’s fate were politically moderate college-educated suburbanites, who made their presence felt as an electoral force first in the 2018 midterm elections, when a historic wave of female candidates and voters served as the driving force behind the Democratic sweep to power in the House.\nEven aside from the pandemic, the 2020 campaign unfolded against a backdrop of national tumult unequaled in recent history, including the House’s vote to impeach the president less than a year ago, a national wave of protests over racial injustice last spring, spasms of civil unrest throughout the summer, the death of a Supreme Court justice in September and the hospitalization of Mr. Trump in October.\nAlong the way, Mr. Trump played to his conservative base, seeking to divide the nation over race and cultural flash points. He encouraged those fears, and the underlying social divisions that fostered them. And for months he sought to sow doubt over the legitimacy of the political process.\nMr. Biden, in response, offered a message of healing that appealed to Americans from far left to center right. He made common cause by promising relief from the unceasing invective and dishonesty of Mr. Trump’s presidency.\nADVERTISEMENT',
|
||||
},
|
||||
{attributes: {align: 'center'}, insert: '\n'},
|
||||
{
|
||||
attributes: {
|
||||
color: 'black',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/11/07/us/politics/biden-election.html#after-story-ad-5',
|
||||
},
|
||||
insert: 'Continue reading the main story',
|
||||
},
|
||||
{attributes: {align: 'center'}, insert: '\n\n\n'},
|
||||
{
|
||||
insert:
|
||||
'The former vice president also sought to demonstrate his differences with the president with his selection of Ms. Harris, 56, whose presence on the ticket as the daughter of Indian and Jamaican immigrants stood in stark contrast to Mr. Trump’s relentless scapegoating of migrants and members of racial-minority groups.\nMr. Biden will be only the second Catholic to attain the presidency, along with John F. Kennedy.\n',
|
||||
},
|
||||
{
|
||||
insert: {
|
||||
image:
|
||||
'https://static01.nyt.com/images/2020/11/04/us/politics/04bidenwinsHFO-f5/merlin_179592678_1d772458-b4e8-4070-a5be-6aa41b163c76-articleLarge.jpg?quality=75&auto=webp&disable=upscale',
|
||||
},
|
||||
},
|
||||
{insert: '\n\nImage\n\n'},
|
||||
{
|
||||
attributes: {
|
||||
alt:
|
||||
'Mr. Biden’s election represented the culmination of nearly four years of activism in opposition to Mr. Trump.',
|
||||
},
|
||||
insert: {
|
||||
image:
|
||||
'https://static01.nyt.com/images/2020/11/04/us/politics/04bidenwinsHFO-f5/merlin_179592678_1d772458-b4e8-4070-a5be-6aa41b163c76-articleLarge.jpg?quality=75&auto=webp&disable=upscale',
|
||||
},
|
||||
},
|
||||
{
|
||||
insert:
|
||||
'\n\nMr. Biden’s election represented the culmination of nearly four years of activism in opposition to Mr. Trump.',
|
||||
},
|
||||
{attributes: {color: '#888888'}, insert: 'Credit...'},
|
||||
{insert: '\n\n'},
|
||||
{
|
||||
attributes: {color: '#888888'},
|
||||
insert: 'Kenny Holston for The New York Times',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
'\n\nIn an era when political differences have metastasized into tribal warfare, at least 74 million voters turned to a figure who has become known as the ',
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
color: '#326891',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/06/11/us/politics/joe-biden-funeral-speech.html',
|
||||
},
|
||||
insert: 'eulogist in chief',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
' for his empathy and friendships with Republicans and Democrats alike.\nIn a sign of how much Mr. Trump alienated traditional Republicans, a number of prominent members of the party ',
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
color: '#326891',
|
||||
link:
|
||||
'https://www.nytimes.com/article/republicans-voting-for-biden-not-trump.html',
|
||||
},
|
||||
insert: 'endorsed Mr. Biden’s candidacy',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
', including Cindy McCain, the widow of former Senator John McCain; the party’s other two presidential nominees this century, George W. Bush and Mitt Romney, declined to endorse Mr. Trump.\nYet for all his lofty language about uniting the country, Mr. Biden was a halting candidate who ran a cautious campaign, determined to ensure that the election became a referendum on Mr. Trump. The former vice president fully returned to the campaign trail only around Labor Day, and for weeks he limited his appearances to one state every other day or so. He went west of the Central time zone just once during the general election.\nAs he prepares to take the oath, he will return to Washington confronting a daunting set of crises. Mr. Biden will be pressed to swiftly secure and distribute a safe vaccine for the coronavirus, revive an economy that may be in even more dire shape in January than it is now, and address racial justice and policing issues that this year prompted some of the largest protests in American history.\nAnd he will do so with a Congress that is far more polarized than the Senate he left over a decade ago, with many Republicans having embraced Mr. Trump’s nativist brand of populism and Democrats increasingly responsive to an energized left. If Mr. Biden cannot bridge that divide as president and elicit some cooperation from the G.O.P., he will face immense pressure from his party’s progressive wing to abandon conciliation for a posture of combat.\nADVERTISEMENT',
|
||||
},
|
||||
{attributes: {align: 'center'}, insert: '\n'},
|
||||
{
|
||||
attributes: {
|
||||
color: 'black',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/11/07/us/politics/biden-election.html#after-story-ad-6',
|
||||
},
|
||||
insert: 'Continue reading the main story',
|
||||
},
|
||||
{attributes: {align: 'center'}, insert: '\n\n\n'},
|
||||
{insert: 'Mr. Biden has '},
|
||||
{
|
||||
attributes: {
|
||||
color: '#326891',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/08/20/us/politics/biden-congress.html',
|
||||
},
|
||||
insert: 'held out hope',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
' about working with Republican lawmakers while declining to support his party’s most ambitious goals, like single-payer health care and the Green New Deal; he has resisted structural changes such as ',
|
||||
},
|
||||
{
|
||||
attributes: {
|
||||
color: '#326891',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/10/22/us/politics/biden-supreme-court-packing.html',
|
||||
},
|
||||
insert: 'adding justices to the Supreme Court',
|
||||
},
|
||||
{
|
||||
insert:
|
||||
'.\nThis irked his party’s base but made it difficult for Republicans, from Mr. Trump down the ballot, to portray him as an extremist. Mr. Biden was largely absent from the appeals of G.O.P. candidates, who instead used their advertising to insist that the Democratic Party would be in the hands of more polarizing figures on the left such as Senator Bernie Sanders.\nUnlike the last two Democrats who defeated incumbents after voters tired of Republican leadership, Jimmy Carter and Bill Clinton, Mr. Biden will not arrive in the capital as a youthful outsider. Instead, he will fill out a Democratic leadership triumvirate, which includes Speaker Nancy Pelosi and Senator Chuck Schumer, of lawmakers who are 70 or older.\nMr. Biden alluded to himself during the campaign as a transitional figure who would bring the country out of a crisis and then make way for a new generation. But he has privately rejected suggestions that he commit to serving just a single term, viewing that as an instant guarantee of lame-duck status.\n',
|
||||
},
|
||||
{
|
||||
insert: {
|
||||
image:
|
||||
'https://static01.nyt.com/images/2020/11/04/us/politics/04bidenwinsHFO-f4-sub/merlin_179394966_fe8d015e-36d3-48f3-aa62-e9f6f1eb81fe-articleLarge.jpg?quality=75&auto=webp&disable=upscale',
|
||||
},
|
||||
},
|
||||
{insert: '\n\nImage\n\n'},
|
||||
{
|
||||
attributes: {
|
||||
alt:
|
||||
'As the big cities of the Midwest and West began to report their totals, places like Detroit began to shift the balance of the electoral map in Mr. Biden’s favor.',
|
||||
},
|
||||
insert: {
|
||||
image:
|
||||
'https://static01.nyt.com/images/2020/11/04/us/politics/04bidenwinsHFO-f4-sub/merlin_179394966_fe8d015e-36d3-48f3-aa62-e9f6f1eb81fe-articleLarge.jpg?quality=75&auto=webp&disable=upscale',
|
||||
},
|
||||
},
|
||||
{
|
||||
insert:
|
||||
'\n\nAs the big cities of the Midwest and West began to report their totals, places like Detroit began to shift the balance of the electoral map in Mr. Biden’s favor.',
|
||||
},
|
||||
{attributes: {color: '#888888'}, insert: 'Credit...'},
|
||||
{insert: '\n\n'},
|
||||
{attributes: {color: '#888888'}, insert: 'Erin Schaff/The New York Times'},
|
||||
{
|
||||
insert:
|
||||
'\n\nOne of the most significant tests of Mr. Biden’s presidency will be in how he navigates the widening divisions in his party.\nHe may enjoy a honeymoon, though, because of both the scale of the problems he is grappling with and the president he defeated.\nADVERTISEMENT',
|
||||
},
|
||||
{attributes: {align: 'center'}, insert: '\n'},
|
||||
{
|
||||
attributes: {
|
||||
color: 'black',
|
||||
link:
|
||||
'https://www.nytimes.com/2020/11/07/us/politics/biden-election.html#after-story-ad-7',
|
||||
},
|
||||
insert: 'Continue reading the main story',
|
||||
},
|
||||
{attributes: {align: 'center'}, insert: '\n\n\n'},
|
||||
{
|
||||
insert:
|
||||
'This election represented the culmination of nearly four years of activism organized around opposing Mr. Trump, a movement that began with the Women’s March the day after his inauguration. Indeed, Mr. Biden’s election appeared less the unique achievement of a political standard-bearer than the apex of a political wave touched off by the 2016 election — one that Mr. Biden rode more than he directed it.\nBut Mr. Trump’s job approval rating never hit 50 percent and, when the coronavirus spread nationwide and Mr. Biden effectively claimed the Democratic nomination in March, the president’s hopes of running with a booming economy and against a far-left opponent evaporated at once.\nStill, many Democrats were nervous and some Republicans were defiantly optimistic going into the election, both still gripped by Mr. Trump’s shocker four years ago. And well into the night Tuesday, it seemed as if the president might be able to do it again. But four days later, after a year of trial in America and four turbulent years of the Trump administration, victory was in hand for Mr. Biden.\n\n',
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
import {StyleSheet} from 'react-native';
|
||||
import {COLOR_SCHEME} from "../../utils/Colors";
|
||||
import {SIZE} from "../../utils/SizeUtils";
|
||||
|
||||
export const styles = StyleSheet.create({
|
||||
container: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
alignSelf: 'center',
|
||||
height: '100%',
|
||||
backgroundColor: 'white',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user