Merge branch 'development' of https://github.com/ecency/ecency-mobile into sa/quick-comment-expansion

This commit is contained in:
Sadaqat Ali 2022-04-18 19:34:02 +05:00
commit b6f405c701
11 changed files with 136 additions and 74 deletions

View File

@ -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);

View File

@ -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}

View File

@ -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>

View File

@ -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',

View File

@ -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"

View 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}
];

View File

@ -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);
};

View File

@ -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}
/>
);
}

View File

@ -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}
/>

View File

@ -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}
/>
);

View File

@ -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({