Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit d770b71

Browse files
[DRAFT] User account page & login screen (#10)
* Create the full layout of User's account page * Implement file picker dialog for acount page * Add user's data to the local storage The user's data are kept in the local User instance which is pulled each time the User's account page is entered. The information can be used from the any other component via the Native module. * Catch the exception in case of general window failure When trying to open the window on the separate thread (after launching the coroutine) it is possible that there'll be the exception thrown by the base.h implementation. The reason for specifying the winrt::hresult_error is that it does not inherits from the std::exception so it would be impossible to catch by the universal exception. * Fix: Invalid window handle due when opening FilePicker The FilePicker when opened was throwing the "Invalid window handle" error. This was caused by the native module thread affinity and the fact that the FilePicker should be launched in the UI thread explicitly. The fix for that is to launch the couroutine on the UI context using the UIDispatcher method of React Native Windows. for more details and the reasoning please check: https://github.com/microsoft/react-native-windows/issues/7641 * Navigate between frames using UIDispatcher * Remove user's avatar from the account page
1 parent 95fb97b commit d770b71

File tree

8 files changed

+253
-19
lines changed

8 files changed

+253
-19
lines changed

‎src/UserAccountPanel.js‎

Lines changed: 126 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,36 +7,149 @@ import React from 'react';
77
import {
88
AppRegistry,
99
StyleSheet,
10-
Text,
1110
View,
11+
NativeModules,
12+
Alert,
13+
Image,
14+
TextInput,
15+
Button,
16+
Text,
1217
} from 'react-native';
1318

1419

1520
class UserAccountPanel extends React.Component {
21+
constructor(props) {
22+
super(props);
23+
this.state = {
24+
userName: "",
25+
userEmail: "",
26+
isEditing: false,
27+
}
28+
};
29+
30+
componentDidMount() {
31+
NativeModules.User.getName()
32+
.then(result => this.setState({userName: result}))
33+
.catch(error => Alert.alert("ERROR!", `${error}`));
34+
NativeModules.User.getEmail()
35+
.then(result => this.setState({userEmail: result}))
36+
.catch(error => Alert.alert("ERROR!", `${error}`));
37+
};
38+
39+
userNameOnChange = (text) => {
40+
this.setState({userName: text});
41+
};
42+
43+
userEmailOnChange = (text) => {
44+
this.setState({userEmail: text});
45+
}
46+
47+
48+
quitButtonPressed = () => {
49+
if(this.state.isEditing) {
50+
Alert.alert("Are you sure?", "It looks like you still have unsaved changes, which are going to be lost.",
51+
[
52+
{
53+
text: "No!",
54+
style: "cancel"
55+
},
56+
{
57+
text: "Yes, quit!",
58+
onPress: () => NativeModules.NoteWidgetClickHandler.goToNotesScreen()
59+
}
60+
])
61+
}
62+
else {
63+
NativeModules.NoteWidgetClickHandler.goToNotesScreen();
64+
}
65+
};
66+
67+
saveButtonPressed = () => {
68+
NativeModules.User.setEmail(this.state.userEmail);
69+
NativeModules.User.setName(this.state.userName);
70+
this.setState({isEditing: false});
71+
}
72+
73+
editButtonPressed = () => {
74+
this.setState({isEditing: true});
75+
};
76+
1677

1778
render() {
18-
return(
19-
<View style={styles.panel}>
20-
<View style={styles.panelContent}>
21-
<Text>UserAccountPanel</Text>
22-
<Text>This panel will have all the features of User's account.</Text>
23-
<Text>Further implementation will yet be done!</Text>
79+
return (
80+
<View style={styles.page}>
81+
82+
<View style={styles.mainPanel}>
83+
84+
<View style={styles.detailsRightPanel}>
85+
<Text>User's name:</Text>
86+
<TextInput style={styles.userNameBox}
87+
onChangeText={this.userNameOnChange}
88+
value={this.state.userName}
89+
editable={this.state.isEditing}
90+
/>
91+
92+
<Text>User's email:</Text>
93+
<TextInput style={styles.userEmailBox}
94+
onChangeText={this.userEmailOnChange}
95+
value={this.state.userEmail}
96+
editable={this.state.isEditing}
97+
/>
98+
</View>
99+
</View>
100+
101+
<View style={styles.actionsPanel}>
102+
<Button title={"Quit!"} onPress={this.quitButtonPressed}/>
103+
<Button title={"Edit"} disabled={this.state.isEditing} onPress={this.editButtonPressed}/>
104+
<Button title={"Save"} disabled={!this.state.isEditing} onPress={this.saveButtonPressed}/>
24105
</View>
106+
25107
</View>
26108
);
27109
}
28110
};
29111

30112

31113
const styles = StyleSheet.create({
32-
panel: {
33-
height: 75,
34-
borderColor: "black",
114+
page: {
115+
margin: 40,
116+
},
117+
mainPanel: {
118+
flex: 0,
119+
flexDirection: "row",
120+
height: "85%",
121+
margin: 20
122+
},
123+
avatarLeftPanel: {
124+
width: 300,
125+
},
126+
detailsRightPanel: {
127+
width: "80%"
128+
},
129+
avatarImage: {
130+
width: 200,
131+
height: 200,
132+
borderRadius: 200 / 2,
35133
borderWidth: 1,
36134
},
37-
panelContent: {
38-
flex: 1,
39-
flexDirection: "column",
135+
userEmailBox: {
136+
width: "80%",
137+
margin: 30
138+
},
139+
userNameBox: {
140+
width: "80%",
141+
margin: 30
142+
},
143+
actionsPanel: {
144+
flex: 0,
145+
flexDirection: "row",
146+
justifyContent: "space-evenly",
147+
height: "10%"
148+
},
149+
avatarButton: {
150+
width: 110,
151+
margin: 40,
152+
marginHorizontal: 45,
40153
}
41154
});
42155

‎windows/ReactNativeNotes/NativeModules/NoteWidgetClickHandler.hpp‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,23 @@ namespace ReactNativeNotes
99
REACT_MODULE( NoteWidgetClickHandler );
1010
struct NoteWidgetClickHandler
1111
{
12+
REACT_INIT( Initialize );
13+
void Initialize( const winrt::Microsoft::ReactNative::ReactContext& reactContext ) noexcept
14+
{
15+
context = reactContext;
16+
}
17+
1218
REACT_METHOD( OpenWidget, L"openWidget" );
1319
void OpenWidget( const unsigned int ID ) noexcept
1420
{
15-
NavigateViaMainFrame( L"ReactNativeNotes.NoteWidgetDetailsPage" );
21+
context.UIDispatcher().Post( [this]()->void { NavigateViaMainFrame( L"ReactNativeNotes.NoteWidgetDetailsPage" ); } );
1622
openedID = ID;
1723
}
1824

1925
REACT_METHOD( GoToNotesScreen, L"goToNotesScreen" );
2026
void GoToNotesScreen() noexcept
2127
{
22-
NavigateViaMainFrame( L"ReactNativeNotes.MainPage" );
28+
context.UIDispatcher().Post( [this]()->void { NavigateViaMainFrame( L"ReactNativeNotes.MainPage" ); } );
2329
}
2430

2531
REACT_METHOD( OpenedNoteID, L"openedNoteID" );
@@ -30,6 +36,8 @@ namespace ReactNativeNotes
3036

3137

3238
private:
39+
winrt::Microsoft::ReactNative::ReactContext context;
40+
3341
void NavigateViaMainFrame( const winrt::hstring pageName )
3442
{
3543
auto pageToNavigateTo = winrt::Windows::UI::Xaml::Interop::TypeName
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
#pragma once
2+
3+
#include "pch.h"
4+
#include "NativeModules.h"
5+
#include <algorithm>
6+
#include <string>
7+
8+
9+
namespace ReactNativeNotes
10+
{
11+
REACT_MODULE( FilePicker );
12+
struct FilePicker
13+
{
14+
REACT_INIT( Initialize );
15+
void Initialize( const winrt::Microsoft::ReactNative::ReactContext& reactContext ) noexcept
16+
{
17+
context = reactContext;
18+
}
19+
20+
REACT_METHOD( OpenFile, L"openFile" );
21+
void OpenFile( React::ReactPromise<React::JSValue> result ) noexcept
22+
{
23+
context.UIDispatcher().Post( [this, result{ std::move( result ) }]()->void { LaunchPicker( result ); } );
24+
}
25+
26+
winrt::fire_and_forget LaunchPicker( React::ReactPromise<React::JSValue> result ) noexcept
27+
{
28+
winrt::Windows::Storage::Pickers::FileOpenPicker openPicker;
29+
openPicker.ViewMode( winrt::Windows::Storage::Pickers::PickerViewMode::Thumbnail );
30+
openPicker.FileTypeFilter().ReplaceAll( { L".jpg", L".jpeg", L".png" } );
31+
32+
try
33+
{
34+
winrt::Windows::Storage::StorageFile file = co_await openPicker.PickSingleFileAsync();
35+
if( file != nullptr )
36+
{
37+
std::string s = winrt::to_string( file.Path() );
38+
result.Resolve( React::JSValue( s ) );
39+
}
40+
else
41+
{
42+
result.Reject( L"Couldn't load the selected file!" );
43+
}
44+
}
45+
catch( const winrt::hresult_error& e )
46+
{
47+
result.Reject( e.message().c_str() );
48+
}
49+
}
50+
51+
winrt::Microsoft::ReactNative::ReactContext context;
52+
};
53+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#pragma once
2+
3+
#include "pch.h"
4+
#include "NativeModules.h"
5+
6+
7+
namespace ReactNativeNotes
8+
{
9+
REACT_MODULE( User );
10+
struct User
11+
{
12+
public:
13+
REACT_METHOD( GetName, L"getName" );
14+
void GetName( React::ReactPromise<React::JSValue> result ) noexcept
15+
{
16+
result.Resolve( React::JSValue( name ) );
17+
}
18+
19+
REACT_METHOD( SetName, L"setName" );
20+
void SetName( const std::string& name ) noexcept
21+
{
22+
this->name = name;
23+
}
24+
25+
REACT_METHOD( GetEmail, L"getEmail" );
26+
void GetEmail( React::ReactPromise<React::JSValue> result ) noexcept
27+
{
28+
result.Resolve( React::JSValue( email ) );
29+
}
30+
31+
REACT_METHOD( SetEmail, L"setEmail" );
32+
void SetEmail( const std::string& email ) noexcept
33+
{
34+
this->email = email;
35+
}
36+
37+
private:
38+
std::string name;
39+
std::string email;
40+
};
41+
}

‎windows/ReactNativeNotes/ReactNativeNotes.vcxproj‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,19 @@
9898
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
9999
<ClCompile>
100100
<PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
101+
<EnableModules Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">true</EnableModules>
102+
<EnableModules Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">true</EnableModules>
103+
<EnableModules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</EnableModules>
104+
<EnableModules Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</EnableModules>
101105
</ClCompile>
102106
</ItemDefinitionGroup>
103107
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
104108
<ClCompile>
105109
<PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
110+
<EnableModules Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</EnableModules>
111+
<EnableModules Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</EnableModules>
112+
<EnableModules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</EnableModules>
113+
<EnableModules Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</EnableModules>
106114
</ClCompile>
107115
</ItemDefinitionGroup>
108116
<ItemGroup>
@@ -122,14 +130,16 @@
122130
<ClInclude Include="NativeModules\NoteWidgetClickHandler.hpp" />
123131
<ClInclude Include="NativeModules\Repository\NoteModel.hpp" />
124132
<ClInclude Include="NativeModules\Repository\Repository.hpp" />
125-
<ClInclude Include="NotesPage.h">
126-
<DependentUpon>NotesPage.xaml</DependentUpon>
127-
<SubType>Code</SubType>
128-
</ClInclude>
133+
<ClInclude Include="NativeModules\UserAccount\FilePicker.hpp" />
134+
<ClInclude Include="NativeModules\UserAccount\User.hpp" />
129135
<ClInclude Include="NoteWidgetDetailsPage.h">
130136
<DependentUpon>NoteWidgetDetailsPage.xaml</DependentUpon>
131137
<SubType>Code</SubType>
132138
</ClInclude>
139+
<ClInclude Include="NotesPage.h">
140+
<DependentUpon>NotesPage.xaml</DependentUpon>
141+
<SubType>Code</SubType>
142+
</ClInclude>
133143
<ClInclude Include="ReactPackageProvider.h" />
134144
<ClInclude Include="AutolinkedNativeModules.g.h" />
135145
<ClInclude Include="pch.h" />

‎windows/ReactNativeNotes/ReactNativeNotes.vcxproj.filters‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
<ClInclude Include="NativeModules\Repository\Repository.hpp" />
4040
<ClInclude Include="NativeModules\DatabaseHandler.hpp" />
4141
<ClInclude Include="NativeModules\NoteWidgetClickHandler.hpp" />
42+
<ClInclude Include="NativeModules\UserAccount\FilePicker.hpp" />
43+
<ClInclude Include="NativeModules\UserAccount\User.hpp" />
4244
</ItemGroup>
4345
<ItemGroup>
4446
<Image Include="Assets\Wide310x150Logo.scale-200.png">

‎windows/ReactNativeNotes/ReactPackageProvider.cpp‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
#include "NativeModules/DatabaseHandler.hpp"
66
#include "NativeModules/NoteWidgetClickHandler.hpp"
77
#include "NativeModules/Repository/Repository.hpp"
8+
#include "NativeModules/UserAccount/FilePicker.hpp"
9+
#include "NativeModules/UserAccount/User.hpp"
10+
811

912
using namespace winrt::Microsoft::ReactNative;
1013

‎windows/ReactNativeNotes/pch.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
#include <winrt/Windows.UI.Xaml.Media.Animation.h>
2020
#include <winrt/Windows.ApplicationModel.Core.h>
2121
#include <winrt/Windows.UI.ViewManagement.h>
22+
#include "winrt/Windows.Storage.Pickers.h"
23+
#include "winrt/Windows.Storage.Pickers.Provider.h"
24+
#include "winrt/Windows.System.h"
25+
#include "winrt/Windows.UI.Core.h"
2226

2327
#include <winrt/Microsoft.ReactNative.h>
2428

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /