mirror of
https://github.com/ecency/ecency-mobile.git
synced 2024-12-30 00:52:42 +03:00
Merge branch 'development' of https://github.com/ecency/ecency-mobile into sa/quick-comment-expansion
This commit is contained in:
commit
b6f405c701
@ -33,6 +33,7 @@ public class MainActivity extends ReactActivity {
|
||||
setIntent(intent);
|
||||
}
|
||||
|
||||
//native side reference: https://github.com/facebook/react-native/issues/28823#issuecomment-642032481
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
@ -75,7 +75,7 @@ const DropdownButtonView = ({
|
||||
renderRowProps={{ underlayColor: EStyleSheet.value('$modalBackground'), style:styles.rowWrapper}}
|
||||
style={[!style ? styles.button : style]}
|
||||
textStyle={[textStyle || styles.buttonText]}
|
||||
dropdownStyle={[styles.dropdown, dropdownStyle, !selectedOptionIndex && { height: 35 * (options.length + 1) }]}
|
||||
dropdownStyle={[styles.dropdown, dropdownStyle, { height: 32 * (options.length + 1) }]}
|
||||
dropdownTextStyle={[dropdownTextStyle || styles.dropdownText]}
|
||||
dropdownTextHighlightStyle={styles.dropdownTextHighlight}
|
||||
options={options}
|
||||
|
@ -24,6 +24,8 @@ class NotificationView extends PureComponent {
|
||||
* ------------------------------------------------
|
||||
* @prop { type } name - Description....
|
||||
*/
|
||||
listRef = null;
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
@ -37,6 +39,7 @@ class NotificationView extends PureComponent {
|
||||
selectedFilter: 'activities',
|
||||
selectedIndex: 0,
|
||||
};
|
||||
this.listRef = React.createRef();
|
||||
}
|
||||
|
||||
// Component Life Cycles
|
||||
@ -44,12 +47,15 @@ class NotificationView extends PureComponent {
|
||||
// Component Functions
|
||||
|
||||
_handleOnDropdownSelect = async (index) => {
|
||||
const { getActivities, changeSelectedFilter } = this.props;
|
||||
const { filters } = this.state;
|
||||
const { getActivities, changeSelectedFilter, } = this.props;
|
||||
const { filters, contentOffset } = this.state;
|
||||
|
||||
this.setState({ selectedFilter: filters[index].key, selectedIndex: index });
|
||||
await changeSelectedFilter(filters[index].key, index);
|
||||
getActivities(filters[index].key, false);
|
||||
const _selectedFilter = filters[index].key;
|
||||
|
||||
this.setState({ selectedFilter: _selectedFilter, selectedIndex: index, contentOffset });
|
||||
await changeSelectedFilter(_selectedFilter, index);
|
||||
getActivities(_selectedFilter, false);
|
||||
this.listRef.current?.scrollToOffset({ x: 0, y: 0, animated: false });
|
||||
};
|
||||
|
||||
_renderList = (data) => {
|
||||
@ -73,11 +79,11 @@ class NotificationView extends PureComponent {
|
||||
};
|
||||
|
||||
_renderFooterLoading = () => {
|
||||
const { loading, notifications } = this.props;
|
||||
if (loading && notifications.length > 0) {
|
||||
const { isLoading } = this.props;
|
||||
if (isLoading) {
|
||||
return (
|
||||
<View style={styles.flatlistFooter}>
|
||||
<ActivityIndicator animating size="large" />
|
||||
<ActivityIndicator animating />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@ -133,8 +139,8 @@ class NotificationView extends PureComponent {
|
||||
let sectionIndex = -1;
|
||||
return notifications.map((item) => {
|
||||
const timeIndex = this._getTimeListIndex(item.timestamp);
|
||||
if(timeIndex !== sectionIndex && timeIndex > sectionIndex){
|
||||
if(sectionIndex === -1){
|
||||
if (timeIndex !== sectionIndex && timeIndex > sectionIndex) {
|
||||
if (sectionIndex === -1) {
|
||||
item.firstSection = true;
|
||||
}
|
||||
item.sectionTitle = notificationArray[timeIndex].title;
|
||||
@ -144,7 +150,7 @@ class NotificationView extends PureComponent {
|
||||
});
|
||||
|
||||
// return notificationArray.filter((item) => item.data.length > 0).map((item, index)=>{item.index = index; return item});
|
||||
};
|
||||
};
|
||||
|
||||
_getTimeListIndex = (timestamp) => {
|
||||
if (isToday(timestamp)) {
|
||||
@ -170,7 +176,7 @@ class NotificationView extends PureComponent {
|
||||
return 5;
|
||||
};
|
||||
|
||||
|
||||
|
||||
_getActivityIndicator = () => (
|
||||
<View style={styles.loading}>
|
||||
<ActivityIndicator animating size="large" />
|
||||
@ -178,26 +184,26 @@ class NotificationView extends PureComponent {
|
||||
);
|
||||
|
||||
|
||||
_renderSectionHeader = ({ section: { title, index} }) => (
|
||||
_renderSectionHeader = ({ section: { title, index } }) => (
|
||||
<ContainerHeader hasSeperator={index !== 0} isBoldTitle title={title} key={title} />
|
||||
)
|
||||
|
||||
|
||||
_renderItem = ({ item }) => (
|
||||
<>
|
||||
{item.sectionTitle && <ContainerHeader hasSeperator={!item.firstSection} isBoldTitle title={item.sectionTitle}/>}
|
||||
<NotificationLine
|
||||
notification={item}
|
||||
handleOnPressNotification={this.props.navigateToNotificationRoute}
|
||||
handleOnUserPress={()=>{this.props.handleOnUserPress(item.source)}}
|
||||
globalProps={this.props.globalProps}
|
||||
/>
|
||||
</>
|
||||
{item.sectionTitle && <ContainerHeader hasSeperator={!item.firstSection} isBoldTitle title={item.sectionTitle} />}
|
||||
<NotificationLine
|
||||
notification={item}
|
||||
handleOnPressNotification={this.props.navigateToNotificationRoute}
|
||||
handleOnUserPress={() => { this.props.handleOnUserPress(item.source) }}
|
||||
globalProps={this.props.globalProps}
|
||||
/>
|
||||
</>
|
||||
)
|
||||
|
||||
|
||||
render() {
|
||||
const { readAllNotification, getActivities, isNotificationRefreshing, intl } = this.props;
|
||||
const { readAllNotification, getActivities, isNotificationRefreshing, intl, isLoading } = this.props;
|
||||
const { filters, selectedFilter, selectedIndex } = this.state;
|
||||
const _notifications = this._getNotificationsArrays();
|
||||
|
||||
@ -217,32 +223,35 @@ class NotificationView extends PureComponent {
|
||||
/>
|
||||
<ThemeContainer>
|
||||
{({ isDarkTheme }) =>
|
||||
_notifications && _notifications.length > 0 ? (
|
||||
<FlatList
|
||||
data={_notifications}
|
||||
keyExtractor={(item, index) => `${item.id}-${index}`}
|
||||
onEndReached={() => getActivities(selectedFilter, true)}
|
||||
onEndReachedThreshold={0.3}
|
||||
ListFooterComponent={this._renderFooterLoading}
|
||||
ListEmptyComponent={<ListPlaceHolder />}
|
||||
contentContainerStyle={styles.listContentContainer}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={isNotificationRefreshing}
|
||||
onRefresh={() => getActivities(selectedFilter)}
|
||||
progressBackgroundColor="#357CE6"
|
||||
tintColor={!isDarkTheme ? '#357ce6' : '#96c0ff'}
|
||||
titleColor="#fff"
|
||||
colors={['#fff']}
|
||||
/>
|
||||
|
||||
<FlatList
|
||||
ref={this.listRef}
|
||||
data={_notifications}
|
||||
keyExtractor={(item, index) => `${item.id}-${index}`}
|
||||
onEndReached={() => getActivities(selectedFilter, true)}
|
||||
onEndReachedThreshold={0.3}
|
||||
ListFooterComponent={this._renderFooterLoading}
|
||||
ListEmptyComponent={
|
||||
isLoading ? <ListPlaceHolder/> : (
|
||||
<Text style={globalStyles.hintText}>
|
||||
{intl.formatMessage({ id: 'notification.noactivity' })}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
renderItem={this._renderItem}
|
||||
/>
|
||||
) : (
|
||||
<Text style={globalStyles.hintText}>
|
||||
{intl.formatMessage({ id: 'notification.noactivity' })}
|
||||
</Text>
|
||||
)
|
||||
contentContainerStyle={styles.listContentContainer}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={isNotificationRefreshing}
|
||||
onRefresh={() => getActivities(selectedFilter)}
|
||||
progressBackgroundColor="#357CE6"
|
||||
tintColor={!isDarkTheme ? '#357ce6' : '#96c0ff'}
|
||||
titleColor="#fff"
|
||||
colors={['#fff']}
|
||||
/>
|
||||
}
|
||||
renderItem={this._renderItem}
|
||||
/>
|
||||
|
||||
}
|
||||
</ThemeContainer>
|
||||
</View>
|
||||
|
@ -28,9 +28,11 @@ export default EStyleSheet.create({
|
||||
textAlign: 'left',
|
||||
},
|
||||
dropdownStyle: {
|
||||
marginTop: 15,
|
||||
marginTop: 4,
|
||||
minWidth: 192,
|
||||
width: 192,
|
||||
borderWidth: EStyleSheet.hairlineWidth,
|
||||
borderColor: '$primaryDarkGray',
|
||||
},
|
||||
dropdownButtonStyle: {
|
||||
borderColor: '$primaryGray',
|
||||
|
@ -217,7 +217,7 @@
|
||||
"currency": "Currency",
|
||||
"language": "Language",
|
||||
"server": "Server",
|
||||
"dark_theme": "Dark Theme",
|
||||
"color_theme": "Appearance",
|
||||
"push_notification": "Push Notification",
|
||||
"notification": {
|
||||
"follow": "Follow",
|
||||
@ -240,6 +240,11 @@
|
||||
"always_hide": "Always hide",
|
||||
"always_warn": "Always warn"
|
||||
},
|
||||
"theme":{
|
||||
"system": "Device settings",
|
||||
"light": "Light",
|
||||
"dark": "Dark"
|
||||
},
|
||||
"feedback_success": "Email successfully open",
|
||||
"feedback_fail": "Email client could not open",
|
||||
"server_fail": "Server not available"
|
||||
|
6
src/constants/options/theme.ts
Normal file
6
src/constants/options/theme.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export default [
|
||||
{key:'settings.theme.system', value: null},
|
||||
{key:'settings.theme.light', value: false},
|
||||
{key:'settings.theme.dark', value: true}
|
||||
];
|
||||
|
@ -38,6 +38,7 @@ import {
|
||||
setVersionForWelcomeModal,
|
||||
getLastUpdateCheck,
|
||||
setLastUpdateCheck,
|
||||
getTheme,
|
||||
} from '../../../realm/realm';
|
||||
import { getUser, getPost, getDigitPinCode, getMutes } from '../../../providers/hive/dhive';
|
||||
import { getUser as getEcencyUser } from '../../../providers/ecency/ePoint';
|
||||
@ -153,13 +154,7 @@ class ApplicationContainer extends Component {
|
||||
AppState.addEventListener('change', this._handleAppStateChange);
|
||||
setPreviousAppState();
|
||||
|
||||
//use Appearance.addChangeListener here to change app theme on the fly
|
||||
//native side reference: https://github.com/facebook/react-native/issues/28823#issuecomment-642032481
|
||||
this.removeAppearanceListener = Appearance.addChangeListener(({ colorScheme }) => {
|
||||
console.log('OS color scheme changed', colorScheme);
|
||||
const _isDarkMode = colorScheme === 'dark';
|
||||
dispatch(isDarkTheme(_isDarkMode));
|
||||
});
|
||||
this.removeAppearanceListener = Appearance.addChangeListener(this._appearanceChangeListener);
|
||||
|
||||
this._createPushListener();
|
||||
|
||||
@ -275,6 +270,17 @@ class ApplicationContainer extends Component {
|
||||
});
|
||||
};
|
||||
|
||||
//change app theme on the fly
|
||||
_appearanceChangeListener = ({ colorScheme }) => {
|
||||
console.log('OS color scheme changed', colorScheme);
|
||||
const { dispatch } = this.props;
|
||||
getTheme().then((darkThemeSetting) => {
|
||||
if (darkThemeSetting === null) {
|
||||
dispatch(isDarkTheme(colorScheme === 'dark'));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
_handleOpenURL = (event) => {
|
||||
this._handleDeepLink(event.url);
|
||||
};
|
||||
|
@ -7,7 +7,6 @@ import { injectIntl } from 'react-intl';
|
||||
|
||||
// Actions and Services
|
||||
import { unionBy } from 'lodash';
|
||||
import reactotron from 'reactotron-react-native';
|
||||
import { getNotifications, markNotifications } from '../../../providers/ecency/ecency';
|
||||
import { updateUnreadActivityCount } from '../../../redux/actions/accountAction';
|
||||
|
||||
@ -25,8 +24,9 @@ class NotificationContainer extends Component {
|
||||
super(props);
|
||||
this.state = {
|
||||
notifications: [],
|
||||
notificationsMap: new Map(),
|
||||
lastNotificationId: null,
|
||||
isRefreshing: false,
|
||||
isRefreshing: true,
|
||||
isLoading: false,
|
||||
selectedFilter: 'activities',
|
||||
endOfNotification: false,
|
||||
@ -42,7 +42,7 @@ class NotificationContainer extends Component {
|
||||
}
|
||||
|
||||
_getActivities = (type = 'activities', loadMore = false) => {
|
||||
const { lastNotificationId, notifications, endOfNotification, isLoading } = this.state;
|
||||
const { lastNotificationId, endOfNotification, isLoading, notificationsMap } = this.state;
|
||||
const since = loadMore ? lastNotificationId : null;
|
||||
|
||||
if (isLoading) {
|
||||
@ -65,8 +65,12 @@ class NotificationContainer extends Component {
|
||||
isLoading: false,
|
||||
});
|
||||
} else {
|
||||
const _notifications = loadMore
|
||||
? unionBy(notificationsMap.get(type) || [], res, 'id')
|
||||
: res;
|
||||
notificationsMap.set(type, _notifications);
|
||||
this.setState({
|
||||
notifications: loadMore ? unionBy(notifications, res, 'id') : res,
|
||||
notificationsMap,
|
||||
lastNotificationId: lastId,
|
||||
isRefreshing: false,
|
||||
isLoading: false,
|
||||
@ -166,7 +170,7 @@ class NotificationContainer extends Component {
|
||||
};
|
||||
|
||||
_changeSelectedFilter = async (value, ind) => {
|
||||
await this.setState({ selectedFilter: value, endOfNotification: false, selectedIndex: ind });
|
||||
this.setState({ selectedFilter: value, endOfNotification: false, selectedIndex: ind });
|
||||
};
|
||||
|
||||
UNSAFE_componentWillReceiveProps(nextProps) {
|
||||
@ -183,12 +187,13 @@ class NotificationContainer extends Component {
|
||||
|
||||
render() {
|
||||
const { isLoggedIn, globalProps } = this.props;
|
||||
const { notifications, isRefreshing } = this.state;
|
||||
const { notificationsMap, selectedFilter, isRefreshing, isLoading } = this.state;
|
||||
|
||||
const _notifications = notificationsMap.get(selectedFilter) || [];
|
||||
return (
|
||||
<NotificationScreen
|
||||
getActivities={this._getActivities}
|
||||
notifications={notifications}
|
||||
notifications={_notifications}
|
||||
navigateToNotificationRoute={this._navigateToNotificationRoute}
|
||||
handleOnUserPress={this._handleOnUserPress}
|
||||
readAllNotification={this._readAllNotification}
|
||||
@ -197,6 +202,7 @@ class NotificationContainer extends Component {
|
||||
isLoggedIn={isLoggedIn}
|
||||
changeSelectedFilter={this._changeSelectedFilter}
|
||||
globalProps={globalProps}
|
||||
isLoading={isLoading}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ const NotificationScreen = ({
|
||||
handleOnUserPress,
|
||||
readAllNotification,
|
||||
isNotificationRefreshing,
|
||||
isLoading,
|
||||
changeSelectedFilter,
|
||||
globalProps,
|
||||
}) => {
|
||||
@ -47,6 +48,7 @@ const NotificationScreen = ({
|
||||
handleOnUserPress={handleOnUserPress}
|
||||
readAllNotification={readAllNotification}
|
||||
isNotificationRefreshing={isNotificationRefreshing}
|
||||
isLoading={isLoading}
|
||||
changeSelectedFilter={changeSelectedFilter}
|
||||
globalProps={globalProps}
|
||||
/>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Platform, Alert } from 'react-native';
|
||||
import { Platform, Alert, Appearance } from 'react-native';
|
||||
import { connect } from 'react-redux';
|
||||
import { Client } from '@hiveio/dhive';
|
||||
import VersionNumber from 'react-native-version-number';
|
||||
@ -7,6 +7,8 @@ import Config from 'react-native-config';
|
||||
import { injectIntl } from 'react-intl';
|
||||
import messaging from '@react-native-firebase/messaging';
|
||||
import { languageRestart } from '../../../utils/I18nUtils';
|
||||
import THEME_OPTIONS from '../../../constants/options/theme';
|
||||
|
||||
// Realm
|
||||
import {
|
||||
getExistUser,
|
||||
@ -22,6 +24,7 @@ import {
|
||||
setAuthStatus,
|
||||
setExistUser,
|
||||
removeAllUserData,
|
||||
getTheme,
|
||||
} from '../../../realm/realm';
|
||||
|
||||
// Services and Actions
|
||||
@ -88,6 +91,12 @@ class SettingsContainer extends Component {
|
||||
serverList: SERVER_LIST,
|
||||
}),
|
||||
);
|
||||
|
||||
getTheme().then((themeSetting) => {
|
||||
this.setState({
|
||||
themeSetting,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Component Functions
|
||||
@ -113,6 +122,18 @@ class SettingsContainer extends Component {
|
||||
setNsfw2DB(action);
|
||||
break;
|
||||
|
||||
case 'theme':
|
||||
let setting = THEME_OPTIONS[action].value;
|
||||
const systemTheme = Appearance.getColorScheme();
|
||||
|
||||
dispatch(isDarkTheme(setting === null ? systemTheme === 'dark' : setting));
|
||||
|
||||
setTheme(setting);
|
||||
this.setState({
|
||||
themeSetting: setting,
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -202,11 +223,6 @@ class SettingsContainer extends Component {
|
||||
this._handleNotification(action, actionType);
|
||||
break;
|
||||
|
||||
case 'theme':
|
||||
dispatch(isDarkTheme(action));
|
||||
setTheme(action);
|
||||
break;
|
||||
|
||||
case 'default_footer':
|
||||
dispatch(isDefaultFooter(action));
|
||||
// setDefaultFooter(action);
|
||||
@ -452,7 +468,7 @@ class SettingsContainer extends Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { serverList, isNotificationMenuOpen, isLoading } = this.state;
|
||||
const { serverList, isNotificationMenuOpen, isLoading, themeSetting } = this.state;
|
||||
|
||||
return (
|
||||
<SettingsScreen
|
||||
@ -461,6 +477,7 @@ class SettingsContainer extends Component {
|
||||
isNotificationMenuOpen={isNotificationMenuOpen}
|
||||
handleOnButtonPress={this._handleButtonPress}
|
||||
isLoading={isLoading}
|
||||
themeSetting={themeSetting}
|
||||
{...this.props}
|
||||
/>
|
||||
);
|
||||
|
@ -10,6 +10,7 @@ import { groomingServerName } from '../../../utils/settings';
|
||||
import LANGUAGE, { VALUE as LANGUAGE_VALUE } from '../../../constants/options/language';
|
||||
import CURRENCY, { VALUE as CURRENCY_VALUE } from '../../../constants/options/currency';
|
||||
import NSFW from '../../../constants/options/nsfw';
|
||||
import THEME_OPTIONS from '../../../constants/options/theme';
|
||||
|
||||
// Components
|
||||
import { BasicHeader, SettingsItem, CollapsibleCard } from '../../../components';
|
||||
@ -21,6 +22,7 @@ const SettingsScreen = ({
|
||||
handleOnChange,
|
||||
intl,
|
||||
isDarkTheme,
|
||||
themeSetting,
|
||||
isPinCodeOpen,
|
||||
isLoggedIn,
|
||||
isNotificationSettingsOpen,
|
||||
@ -118,13 +120,19 @@ const SettingsScreen = ({
|
||||
/>
|
||||
<SettingsItem
|
||||
title={intl.formatMessage({
|
||||
id: 'settings.dark_theme',
|
||||
id: 'settings.color_theme',
|
||||
})}
|
||||
type="toggle"
|
||||
type="dropdown"
|
||||
actionType="theme"
|
||||
isOn={isDarkTheme}
|
||||
options={THEME_OPTIONS.map((item) =>
|
||||
intl.formatMessage({
|
||||
id: item.key,
|
||||
}),
|
||||
)}
|
||||
selectedOptionIndex={THEME_OPTIONS.findIndex((item) => item.value === themeSetting)}
|
||||
handleOnChange={handleOnChange}
|
||||
/>
|
||||
|
||||
{!!isLoggedIn && (
|
||||
<SettingsItem
|
||||
title={intl.formatMessage({
|
||||
|
Loading…
Reference in New Issue
Block a user