add a way to click the toast to turn on microphone to show the settings
This commit is contained in:
parent
f4fb56d9ed
commit
eb30c7823c
|
@ -772,7 +772,7 @@
|
|||
"description": "Shown if the user attempts to send an audio message without audio permssions turned on"
|
||||
},
|
||||
"audioPermissionNeeded": {
|
||||
"message": "Session needs microphone access to send audio messages.",
|
||||
"message": "You can enable microphone access under: Settings (Gear icon) => Privacy",
|
||||
"description": "Shown if the user attempts to send an audio message without audio permssions turned on",
|
||||
"androidKey": "ConversationActivity_to_send_audio_messages_allow_signal_access_to_your_microphone"
|
||||
},
|
||||
|
|
|
@ -630,7 +630,7 @@
|
|||
"description": "In Android theme, shown in quote if you or someone else replies to you"
|
||||
},
|
||||
"audioPermissionNeeded": {
|
||||
"message": "Pour envoyer des messages audio, autorisez Session à accéder à votre microphone.",
|
||||
"message": "Vous pouvez autoriser l'accès au microphone via: Paramètres (icon roue dentée) => Confidentialité.",
|
||||
"description": "Shown if the user attempts to send an audio message without audio permssions turned on"
|
||||
},
|
||||
"allowAccess": {
|
||||
|
|
|
@ -33,14 +33,15 @@ interface Props {
|
|||
unreadMessageCount: number;
|
||||
searchResults?: SearchResultsProps;
|
||||
searchTerm: string;
|
||||
|
||||
focusedSection: SectionType;
|
||||
focusSection: (section: SectionType) => void;
|
||||
focusedSettingsSection?: SessionSettingCategory;
|
||||
showLeftPaneSection: (section: SectionType) => void;
|
||||
showSettingsSection: (section: SessionSettingCategory) => void;
|
||||
|
||||
isExpired: boolean;
|
||||
|
||||
openConversationExternal: (id: string, messageId?: string) => void;
|
||||
showSessionSettingsCategory: (category: SessionSettingCategory) => void;
|
||||
showSessionViewConversation: () => void;
|
||||
settingsCategory?: SessionSettingCategory;
|
||||
updateSearchTerm: (searchTerm: string) => void;
|
||||
search: (query: string, options: SearchOptions) => void;
|
||||
clearSearch: () => void;
|
||||
|
@ -56,12 +57,7 @@ export class LeftPane extends React.Component<Props> {
|
|||
|
||||
public handleSectionSelected(section: SectionType) {
|
||||
this.props.clearSearch();
|
||||
this.props.focusSection(section);
|
||||
if (section === SectionType.Settings) {
|
||||
this.props.showSessionSettingsCategory(SessionSettingCategory.Appearance);
|
||||
} else {
|
||||
this.props.showSessionViewConversation();
|
||||
}
|
||||
this.props.showLeftPaneSection(section);
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
|
@ -146,13 +142,14 @@ export class LeftPane extends React.Component<Props> {
|
|||
}
|
||||
|
||||
private renderSettingSection() {
|
||||
const { settingsCategory } = this.props;
|
||||
|
||||
const category = settingsCategory || SessionSettingCategory.Appearance;
|
||||
|
||||
const settingsCategory =
|
||||
this.props.focusedSettingsSection || SessionSettingCategory.Appearance;
|
||||
return (
|
||||
<>
|
||||
<LeftPaneSettingSection {...this.props} settingsCategory={category} />
|
||||
<LeftPaneSettingSection
|
||||
{...this.props}
|
||||
settingsCategory={settingsCategory}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
import React from 'react';
|
||||
|
||||
import { DefaultTheme } from 'styled-components';
|
||||
import { SmartSessionConversation } from '../state/smart/SessionConversation';
|
||||
import {
|
||||
SessionSettingCategory,
|
||||
SmartSettingsView,
|
||||
} from './session/settings/SessionSettings';
|
||||
|
||||
const FilteredSettingsView = SmartSettingsView as any;
|
||||
|
||||
interface Props {
|
||||
focusedSettingsSection?: SessionSettingCategory;
|
||||
}
|
||||
|
||||
export class SessionMainPanel extends React.Component<Props> {
|
||||
public constructor(props: Props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
public render() {
|
||||
const isSettingsView = this.props.focusedSettingsSection !== undefined;
|
||||
|
||||
return isSettingsView
|
||||
? this.renderSettings()
|
||||
: this.renderSessionConversation();
|
||||
}
|
||||
|
||||
private renderSettings() {
|
||||
const category = this.props.focusedSettingsSection;
|
||||
|
||||
return <FilteredSettingsView category={category} />;
|
||||
}
|
||||
|
||||
private renderSessionConversation() {
|
||||
return (
|
||||
<div className="session-conversation">
|
||||
<SmartSessionConversation />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@ import { deleteAccount } from '../../util/accountManager';
|
|||
|
||||
interface Props {
|
||||
settingsCategory: SessionSettingCategory;
|
||||
showSessionSettingsCategory: (category: SessionSettingCategory) => void;
|
||||
showSettingsSection: (category: SessionSettingCategory) => void;
|
||||
theme: DefaultTheme;
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,6 @@ export class LeftPaneSettingSection extends React.Component<Props, State> {
|
|||
searchQuery: '',
|
||||
};
|
||||
|
||||
this.setCategory = this.setCategory.bind(this);
|
||||
this.onDeleteAccount = this.onDeleteAccount.bind(this);
|
||||
}
|
||||
|
||||
|
@ -67,7 +66,7 @@ export class LeftPaneSettingSection extends React.Component<Props, State> {
|
|||
)}
|
||||
role="link"
|
||||
onClick={() => {
|
||||
this.setCategory(item.id);
|
||||
this.props.showSettingsSection(item.id);
|
||||
}}
|
||||
>
|
||||
<div>
|
||||
|
@ -214,8 +213,4 @@ export class LeftPaneSettingSection extends React.Component<Props, State> {
|
|||
},
|
||||
];
|
||||
}
|
||||
|
||||
public setCategory(category: SessionSettingCategory) {
|
||||
this.props.showSessionSettingsCategory(category);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,59 +1,34 @@
|
|||
import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { getMessageById } from '../../data/data';
|
||||
import { ConversationModel } from '../../models/conversation';
|
||||
import { MessageModel } from '../../models/message';
|
||||
import { getMessageQueue } from '../../session';
|
||||
import { ConversationController } from '../../session/conversations';
|
||||
import { MessageController } from '../../session/messages';
|
||||
import { OpenGroupMessage } from '../../session/messages/outgoing';
|
||||
import { RawMessage } from '../../session/types';
|
||||
import { UserUtils } from '../../session/utils';
|
||||
import { createStore } from '../../state/createStore';
|
||||
import { actions as conversationActions } from '../../state/ducks/conversations';
|
||||
import { actions as userActions } from '../../state/ducks/user';
|
||||
import { SmartLeftPane } from '../../state/smart/LeftPane';
|
||||
import { SmartSessionConversation } from '../../state/smart/SessionConversation';
|
||||
import { SmartSessionMainPanel } from '../../state/smart/SessionMainPanel';
|
||||
import { makeLookup } from '../../util';
|
||||
import {
|
||||
SessionSettingCategory,
|
||||
SmartSettingsView,
|
||||
} from './settings/SessionSettings';
|
||||
|
||||
// Workaround: A react component's required properties are filtering up through connect()
|
||||
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/31363
|
||||
const FilteredLeftPane = SmartLeftPane as any;
|
||||
const FilteredSettingsView = SmartSettingsView as any;
|
||||
|
||||
type Props = {
|
||||
focusedSection: number;
|
||||
};
|
||||
|
||||
type State = {
|
||||
isInitialLoadComplete: boolean;
|
||||
settingsCategory?: SessionSettingCategory;
|
||||
isExpired: boolean;
|
||||
};
|
||||
|
||||
export class SessionInboxView extends React.Component<Props, State> {
|
||||
export class SessionInboxView extends React.Component<any, State> {
|
||||
private store: any;
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isInitialLoadComplete: false,
|
||||
settingsCategory: undefined,
|
||||
isExpired: false,
|
||||
};
|
||||
|
||||
this.showSessionSettingsCategory = this.showSessionSettingsCategory.bind(
|
||||
this
|
||||
);
|
||||
this.showSessionViewConversation = this.showSessionViewConversation.bind(
|
||||
this
|
||||
);
|
||||
|
||||
void this.setupLeftPane();
|
||||
|
||||
// not reactified yet. this is a callback called once we were able to check for expiration of this Session version
|
||||
|
@ -71,46 +46,19 @@ export class SessionInboxView extends React.Component<Props, State> {
|
|||
return <></>;
|
||||
}
|
||||
|
||||
const { settingsCategory } = this.state;
|
||||
|
||||
const isSettingsView = settingsCategory !== undefined;
|
||||
return (
|
||||
<Provider store={this.store}>
|
||||
<div className="gutter">
|
||||
<div className="network-status-container" />
|
||||
{this.renderLeftPane()}
|
||||
</div>
|
||||
{isSettingsView
|
||||
? this.renderSettings()
|
||||
: this.renderSessionConversation()}
|
||||
<SmartSessionMainPanel />
|
||||
</Provider>
|
||||
);
|
||||
}
|
||||
|
||||
private renderLeftPane() {
|
||||
return (
|
||||
<FilteredLeftPane
|
||||
showSessionSettingsCategory={this.showSessionSettingsCategory}
|
||||
showSessionViewConversation={this.showSessionViewConversation}
|
||||
settingsCategory={this.state.settingsCategory}
|
||||
isExpired={this.state.isExpired}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
private renderSettings() {
|
||||
const category =
|
||||
this.state.settingsCategory || SessionSettingCategory.Appearance;
|
||||
|
||||
return <FilteredSettingsView category={category} />;
|
||||
}
|
||||
|
||||
private renderSessionConversation() {
|
||||
return (
|
||||
<div className="session-conversation">
|
||||
<SmartSessionConversation />
|
||||
</div>
|
||||
);
|
||||
return <FilteredLeftPane isExpired={this.state.isExpired} />;
|
||||
}
|
||||
|
||||
private async setupLeftPane() {
|
||||
|
@ -155,12 +103,4 @@ export class SessionInboxView extends React.Component<Props, State> {
|
|||
|
||||
this.setState({ isInitialLoadComplete: true });
|
||||
}
|
||||
|
||||
private showSessionSettingsCategory(category: SessionSettingCategory) {
|
||||
this.setState({ settingsCategory: category });
|
||||
}
|
||||
|
||||
private showSessionViewConversation() {
|
||||
this.setState({ settingsCategory: undefined });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import React, { useContext } from 'react';
|
|||
import { SessionIcon, SessionIconSize, SessionIconType } from './icon/';
|
||||
import { Flex } from './Flex';
|
||||
import styled, { ThemeContext } from 'styled-components';
|
||||
import { noop } from 'lodash';
|
||||
|
||||
export enum SessionToastType {
|
||||
Info = 'info',
|
||||
|
@ -18,6 +19,7 @@ type Props = {
|
|||
icon?: SessionIconType;
|
||||
description?: string;
|
||||
closeToast?: any;
|
||||
onToastClick?: () => void;
|
||||
};
|
||||
|
||||
const TitleDiv = styled.div`
|
||||
|
@ -74,7 +76,12 @@ export const SessionToast = (props: Props) => {
|
|||
}
|
||||
|
||||
return (
|
||||
<Flex container={true} alignItems="center">
|
||||
// tslint:disable-next-line: use-simple-attributes
|
||||
<Flex
|
||||
container={true}
|
||||
alignItems="center"
|
||||
onClick={props?.onToastClick || noop}
|
||||
>
|
||||
<IconDiv>
|
||||
<SessionIcon
|
||||
iconType={toastIcon}
|
||||
|
|
|
@ -31,6 +31,8 @@ import { ConversationController } from '../../../session/conversations';
|
|||
import { ConversationType } from '../../../state/ducks/conversations';
|
||||
import { SessionMemberListItem } from '../SessionMemberListItem';
|
||||
import autoBind from 'auto-bind';
|
||||
import { SectionType } from '../ActionsPanel';
|
||||
import { SessionSettingCategory } from '../settings/SessionSettings';
|
||||
|
||||
export interface ReplyingToMessageProps {
|
||||
convoId: string;
|
||||
|
@ -78,6 +80,8 @@ interface Props {
|
|||
clearAttachments: () => any;
|
||||
removeAttachment: (toRemove: AttachmentType) => void;
|
||||
onChoseAttachments: (newAttachments: Array<File>) => void;
|
||||
showLeftPaneSection: (section: SectionType) => void;
|
||||
showSettingsSection: (category: SessionSettingCategory) => void;
|
||||
theme: DefaultTheme;
|
||||
}
|
||||
|
||||
|
@ -931,7 +935,10 @@ export class SessionCompositionBox extends React.Component<Props, State> {
|
|||
return;
|
||||
}
|
||||
|
||||
ToastUtils.pushAudioPermissionNeeded();
|
||||
ToastUtils.pushAudioPermissionNeeded(() => {
|
||||
this.props.showLeftPaneSection(SectionType.Settings);
|
||||
this.props.showSettingsSection(SessionSettingCategory.Privacy);
|
||||
});
|
||||
}
|
||||
|
||||
private onExitVoiceNoteView() {
|
||||
|
|
|
@ -29,8 +29,6 @@ import { MessageView } from '../../MainViewController';
|
|||
import { pushUnblockToSend } from '../../../session/utils/Toast';
|
||||
import { MessageDetail } from '../../conversation/MessageDetail';
|
||||
import { ConversationController } from '../../../session/conversations';
|
||||
import { PubKey } from '../../../session/types';
|
||||
import { MessageModel } from '../../../models/message';
|
||||
import {
|
||||
getMessageById,
|
||||
getPubkeysInPublicConversation,
|
||||
|
@ -210,6 +208,7 @@ export class SessionConversation extends React.Component<Props, State> {
|
|||
selectedConversation,
|
||||
selectedConversationKey,
|
||||
messages,
|
||||
actions,
|
||||
} = this.props;
|
||||
|
||||
if (!selectedConversation || !messages) {
|
||||
|
@ -308,6 +307,8 @@ export class SessionConversation extends React.Component<Props, State> {
|
|||
onMessageFailure={this.onMessageFailure}
|
||||
onLoadVoiceNoteView={this.onLoadVoiceNoteView}
|
||||
onExitVoiceNoteView={this.onExitVoiceNoteView}
|
||||
showLeftPaneSection={actions.showLeftPaneSection}
|
||||
showSettingsSection={actions.showSettingsSection}
|
||||
quotedMessageProps={quotedMessageProps}
|
||||
removeQuotedMessage={() => {
|
||||
void this.replyToMessage(undefined);
|
||||
|
|
|
@ -35,12 +35,18 @@ export function pushToastWarning(
|
|||
);
|
||||
}
|
||||
|
||||
export function pushToastInfo(id: string, title: string, description?: string) {
|
||||
export function pushToastInfo(
|
||||
id: string,
|
||||
title: string,
|
||||
description?: string,
|
||||
onToastClick?: () => void
|
||||
) {
|
||||
toast.info(
|
||||
<SessionToast
|
||||
title={title}
|
||||
description={description}
|
||||
type={SessionToastType.Info}
|
||||
onToastClick={onToastClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -151,11 +157,12 @@ export function pushMessageDeleteForbidden() {
|
|||
);
|
||||
}
|
||||
|
||||
export function pushAudioPermissionNeeded() {
|
||||
export function pushAudioPermissionNeeded(onClicked: () => void) {
|
||||
pushToastInfo(
|
||||
'audioPermissionNeeded',
|
||||
window.i18n('audioPermissionNeededTitle'),
|
||||
window.i18n('audioPermissionNeeded')
|
||||
window.i18n('audioPermissionNeeded'),
|
||||
onClicked
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,26 +1,52 @@
|
|||
import { SectionType } from '../../components/session/ActionsPanel';
|
||||
import { SessionSettingCategory } from '../../components/session/settings/SessionSettings';
|
||||
|
||||
export const FOCUS_SECTION = 'FOCUS_SECTION';
|
||||
export const FOCUS_SETTINGS_SECTION = 'FOCUS_SETTINGS_SECTION';
|
||||
|
||||
type FocusSectionActionType = {
|
||||
type: 'FOCUS_SECTION';
|
||||
payload: SectionType;
|
||||
};
|
||||
|
||||
function focusSection(section: SectionType): FocusSectionActionType {
|
||||
type FocusSettingsSectionActionType = {
|
||||
type: 'FOCUS_SETTINGS_SECTION';
|
||||
payload: SessionSettingCategory;
|
||||
};
|
||||
|
||||
function showLeftPaneSection(section: SectionType): FocusSectionActionType {
|
||||
return {
|
||||
type: FOCUS_SECTION,
|
||||
payload: section,
|
||||
};
|
||||
}
|
||||
|
||||
type SectionActionTypes =
|
||||
| FocusSectionActionType
|
||||
| FocusSettingsSectionActionType;
|
||||
|
||||
function showSettingsSection(
|
||||
category: SessionSettingCategory
|
||||
): FocusSettingsSectionActionType {
|
||||
return {
|
||||
type: FOCUS_SETTINGS_SECTION,
|
||||
payload: category,
|
||||
};
|
||||
}
|
||||
|
||||
export const actions = {
|
||||
focusSection,
|
||||
showLeftPaneSection,
|
||||
showSettingsSection,
|
||||
};
|
||||
|
||||
const initialState = {
|
||||
focusedSection: SectionType.Message,
|
||||
focusedSettingsSection: undefined,
|
||||
};
|
||||
|
||||
const initialState = { focusedSection: SectionType.Message };
|
||||
export type SectionStateType = {
|
||||
focusedSection: SectionType;
|
||||
focusedSettingsSection?: SessionSettingCategory;
|
||||
};
|
||||
|
||||
export const reducer = (
|
||||
|
@ -30,12 +56,32 @@ export const reducer = (
|
|||
payload,
|
||||
}: {
|
||||
type: string;
|
||||
payload: SectionType;
|
||||
payload: SectionActionTypes;
|
||||
}
|
||||
): SectionStateType => {
|
||||
switch (type) {
|
||||
case FOCUS_SECTION:
|
||||
return { focusedSection: payload };
|
||||
// if we change to something else than settings, reset the focused settings section
|
||||
const castedPayload = (payload as unknown) as SectionType;
|
||||
|
||||
if (castedPayload !== SectionType.Settings) {
|
||||
return {
|
||||
focusedSection: castedPayload,
|
||||
focusedSettingsSection: undefined,
|
||||
};
|
||||
}
|
||||
|
||||
// on click on the gear icon: show the appearance tab by default
|
||||
return {
|
||||
...state,
|
||||
focusedSection: payload,
|
||||
focusedSettingsSection: SessionSettingCategory.Appearance,
|
||||
};
|
||||
case FOCUS_SETTINGS_SECTION:
|
||||
return {
|
||||
...state,
|
||||
focusedSettingsSection: payload,
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import { createSelector } from 'reselect';
|
|||
import { StateType } from '../reducer';
|
||||
import { SectionStateType } from '../ducks/section';
|
||||
import { SectionType } from '../../components/session/ActionsPanel';
|
||||
import { SessionSettingCategory } from '../../components/session/settings/SessionSettings';
|
||||
|
||||
export const getSection = (state: StateType): SectionStateType => state.section;
|
||||
|
||||
|
@ -10,3 +11,9 @@ export const getFocusedSection = createSelector(
|
|||
getSection,
|
||||
(state: SectionStateType): SectionType => state.focusedSection
|
||||
);
|
||||
|
||||
export const getFocusedSettingsSection = createSelector(
|
||||
getSection,
|
||||
(state: SectionStateType): SessionSettingCategory | undefined =>
|
||||
state.focusedSettingsSection
|
||||
);
|
||||
|
|
|
@ -9,7 +9,10 @@ import {
|
|||
getOurPrimaryConversation,
|
||||
} from '../selectors/conversations';
|
||||
import { mapDispatchToProps } from '../actions';
|
||||
import { getFocusedSection } from '../selectors/section';
|
||||
import {
|
||||
getFocusedSection,
|
||||
getFocusedSettingsSection,
|
||||
} from '../selectors/section';
|
||||
import { getTheme } from '../selectors/theme';
|
||||
|
||||
// Workaround: A react component's required properties are filtering up through connect()
|
||||
|
@ -33,6 +36,7 @@ const mapStateToProps = (state: StateType) => {
|
|||
unreadMessageCount: leftPaneList.unreadCount,
|
||||
theme: getTheme(state),
|
||||
focusedSection: getFocusedSection(state),
|
||||
focusedSettingsSection: getFocusedSettingsSection(state),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import { connect } from 'react-redux';
|
||||
import { StateType } from '../reducer';
|
||||
|
||||
import { mapDispatchToProps } from '../actions';
|
||||
import { getFocusedSettingsSection } from '../selectors/section';
|
||||
import { getTheme } from '../selectors/theme';
|
||||
import { SessionMainPanel } from '../../components/SessionMainPanel';
|
||||
|
||||
const mapStateToProps = (state: StateType) => {
|
||||
return {
|
||||
theme: getTheme(state),
|
||||
focusedSettingsSection: getFocusedSettingsSection(state),
|
||||
};
|
||||
};
|
||||
|
||||
const smart = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
||||
export const SmartSessionMainPanel = smart(SessionMainPanel);
|
Loading…
Reference in New Issue