From 7d8bf8a82d2f8eea1b85179c6604aa9aa42e65ca Mon Sep 17 00:00:00 2001 From: Bartosz Klonowski Date: Tue, 6 Apr 2021 12:04:23 +0200 Subject: [PATCH 1/6] Create notes dependning on the number of created notes This implementation adds several methods to the Database handler class: * GetNumberOfNotes - returns the number of notes already created by the user in the system. It considers only the size of the repository, without checking the correctness of the IDs. * DoesIDExists - checks whether the notes with the given ID exists in the Database * GetAllNotes - alternate version of creating the notes keys' method. It returns the array of already created objects containing the Key and it's value. This is experimental and not yet fully tested/supported. Note that the `GetNumberOfNotes` method uses Promise instead of return callback. This is due to the fact of async nature of native modules. So to avoid losing the information of returned value when going out of the return handler, the promise is used which carries the result. --- src/NotesMainPanel.js | 24 ++++++++++++++++--- .../NativeModules/DatabaseHandler.hpp | 24 +++++++++++++++++++ .../NativeModules/Repository/Repository.cpp | 5 ++++ .../NativeModules/Repository/Repository.hpp | 2 ++ 4 files changed, 52 insertions(+), 3 deletions(-) diff --git a/src/NotesMainPanel.js b/src/NotesMainPanel.js index 5aef9d3..4722884 100644 --- a/src/NotesMainPanel.js +++ b/src/NotesMainPanel.js @@ -5,9 +5,11 @@ import React from 'react'; import { + Alert, AppRegistry, Dimensions, FlatList, + NativeModules, StyleSheet, View, } from 'react-native'; @@ -23,14 +25,14 @@ class NotesMainPanel extends React.Component { constructor(props) { super(props); this.state = { - notes: [{key: "1"}, {key: "2"}, {key: "3"}, {key: "4"}, {key: "5"}, {key: "6"}, {key: "7"}, {key: "8"}, {key: "9"}], + notes: [], dimensions: {window, screen}, columns: this.calculateColumnWidth(window), } }; calculateColumnWidth = (window) => { - return Math.floor(window.width / noteWidgetWidth); + return Math.floor(Dimensions.get("window").width / noteWidgetWidth); }; onChange = ({ window, screen }) => { @@ -38,6 +40,7 @@ class NotesMainPanel extends React.Component { }; componentDidMount() { + this.getDataFromDatabase(); Dimensions.addEventListener("change", this.onChange); }; @@ -45,6 +48,21 @@ class NotesMainPanel extends React.Component { Dimensions.removeEventListener("change", this.onChange); }; + createNotesKeys = (numberOfNotes) => { + let allNotesKeys = []; + for(id = 0; id < numberOfNotes; id++) { + const nextObject = {key: id}; + allNotesKeys.push(nextObject); + } + this.setState({notes: allNotesKeys}); + }; + + getDataFromDatabase = () => { + NativeModules.Database.getNumberOfNotes() + .then(result => this.createNotesKeys(result)) + .catch(error => Alert.alert("ERROR!", `Result: ${error}`)); + }; + renderNote = notes => { return }; @@ -52,7 +70,7 @@ class NotesMainPanel extends React.Component { render() { return( - + ); } diff --git a/windows/ReactNativeNotes/NativeModules/DatabaseHandler.hpp b/windows/ReactNativeNotes/NativeModules/DatabaseHandler.hpp index 6c42f35..a001f4f 100644 --- a/windows/ReactNativeNotes/NativeModules/DatabaseHandler.hpp +++ b/windows/ReactNativeNotes/NativeModules/DatabaseHandler.hpp @@ -41,6 +41,30 @@ namespace winrt::ReactNativeNotes::implementation return winrt::to_hstring( data->Read( ID ).ShortPost() ); } + REACT_METHOD( GetNumberOfNotes, L"getNumberOfNotes" ); + void GetNumberOfNotes( React::ReactPromise&& result ) noexcept + { + result.Resolve( React::JSValue( std::to_string(data->Size()) ) ); + } + + REACT_METHOD( DoesIDExists, L"doesIDExists" ); + const bool DoesIDExists( const unsigned int ID ) noexcept + { + return data->Exists( ID ); + } + + REACT_METHOD( GetAllNotesIDs, L"getAllNotesIDs" ); + Microsoft::ReactNative::JSValue GetAllNotesIDs() noexcept + { + Microsoft::ReactNative::JSValueArray keyArray; + for( unsigned int i = 0; i < data->Size(); ++i ) + { + if( data->Exists( i ) ) + keyArray.push_back( Microsoft::ReactNative::JSValueObject{ { "key", i } } ); + } + return Microsoft::ReactNative::JSValue( std::move( keyArray ) ); + } + private: std::unique_ptr data; }; diff --git a/windows/ReactNativeNotes/NativeModules/Repository/Repository.cpp b/windows/ReactNativeNotes/NativeModules/Repository/Repository.cpp index c25b97e..5f41ba3 100644 --- a/windows/ReactNativeNotes/NativeModules/Repository/Repository.cpp +++ b/windows/ReactNativeNotes/NativeModules/Repository/Repository.cpp @@ -40,4 +40,9 @@ namespace winrt::ReactNativeNotes::implementation { return notes.size(); } + + const bool Repository::Exists( const unsigned int ID ) const noexcept + { + return std::find_if( notes.cbegin(), notes.cend(), [=]( const NoteModel& n )->bool { return n.ID() == ID; } ) != notes.cend(); + } } diff --git a/windows/ReactNativeNotes/NativeModules/Repository/Repository.hpp b/windows/ReactNativeNotes/NativeModules/Repository/Repository.hpp index e7a882c..5f7c8c0 100644 --- a/windows/ReactNativeNotes/NativeModules/Repository/Repository.hpp +++ b/windows/ReactNativeNotes/NativeModules/Repository/Repository.hpp @@ -26,6 +26,8 @@ namespace winrt::ReactNativeNotes::implementation unsigned int Size() const noexcept; + const bool Exists( const unsigned int ID ) const noexcept; + private: std::vector notes; }; From 14d3b050ee17fd841253115d09b33b1bd8469f4f Mon Sep 17 00:00:00 2001 From: Bartosz Klonowski Date: Tue, 6 Apr 2021 12:10:53 +0200 Subject: [PATCH 2/6] Go the main page when entering the app --- windows/ReactNativeNotes/App.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/windows/ReactNativeNotes/App.cpp b/windows/ReactNativeNotes/App.cpp index 0cfceaa..89e3048 100644 --- a/windows/ReactNativeNotes/App.cpp +++ b/windows/ReactNativeNotes/App.cpp @@ -53,7 +53,7 @@ void App::OnLaunched(activation::LaunchActivatedEventArgs const& e) super::OnLaunched(e); Frame rootFrame = Window::Current().Content().as(); - rootFrame.Navigate(xaml_typename(), box_value(e.Arguments())); + rootFrame.Navigate(xaml_typename(), box_value(e.Arguments())); } /// From 57741e61e9d4e5727772c319c1578bc49e1e7107 Mon Sep 17 00:00:00 2001 From: Bartosz Klonowski Date: Tue, 6 Apr 2021 13:55:36 +0200 Subject: [PATCH 3/6] Overload the CRUD operations for index The index can now be used as a parameter for all the CRUD operations done on the Repository. This is to allow the easier manipulations when it comes to all notes no matter if they Id matches the db position. The purpose of this implementation is to make sure that in the future the index and the ID will be separate and the logic behind adding/removing and displaying the content will be more flexible. --- .../NativeModules/Repository/Repository.cpp | 17 +++++++++++++++++ .../NativeModules/Repository/Repository.hpp | 3 +++ 2 files changed, 20 insertions(+) diff --git a/windows/ReactNativeNotes/NativeModules/Repository/Repository.cpp b/windows/ReactNativeNotes/NativeModules/Repository/Repository.cpp index 5f41ba3..20c1280 100644 --- a/windows/ReactNativeNotes/NativeModules/Repository/Repository.cpp +++ b/windows/ReactNativeNotes/NativeModules/Repository/Repository.cpp @@ -20,6 +20,14 @@ namespace winrt::ReactNativeNotes::implementation return NoteModel(); } + NoteModel Repository::Read( const int index ) const noexcept + { + if( index >= notes.size() ) + return NoteModel(); + else + return notes.at(index); + } + void Repository::Update( const NoteModel& note ) noexcept { for( unsigned int index = 0; index < notes.size(); ++index ) @@ -36,6 +44,11 @@ namespace winrt::ReactNativeNotes::implementation notes.erase( it ); } + void Repository::Delete( const int index ) noexcept + { + notes.erase( notes.cbegin() + index ); + } + unsigned int Repository::Size() const noexcept { return notes.size(); @@ -45,4 +58,8 @@ namespace winrt::ReactNativeNotes::implementation { return std::find_if( notes.cbegin(), notes.cend(), [=]( const NoteModel& n )->bool { return n.ID() == ID; } ) != notes.cend(); } + const bool Repository::Exists( const int index ) const noexcept + { + return index < notes.size(); + } } diff --git a/windows/ReactNativeNotes/NativeModules/Repository/Repository.hpp b/windows/ReactNativeNotes/NativeModules/Repository/Repository.hpp index 5f7c8c0..81bfe7b 100644 --- a/windows/ReactNativeNotes/NativeModules/Repository/Repository.hpp +++ b/windows/ReactNativeNotes/NativeModules/Repository/Repository.hpp @@ -19,14 +19,17 @@ namespace winrt::ReactNativeNotes::implementation void Create( NoteModel& note ) noexcept; NoteModel Read( const unsigned int ID ) const noexcept; + NoteModel Read( const int index ) const noexcept; void Update( const NoteModel& note ) noexcept; void Delete( const unsigned int ID ) noexcept; + void Delete( const int index ) noexcept; unsigned int Size() const noexcept; const bool Exists( const unsigned int ID ) const noexcept; + const bool Exists( const int index ) const noexcept; private: std::vector notes; From cb8ab1e0653ca0a8fd43647948c68730bbc21c08 Mon Sep 17 00:00:00 2001 From: Bartosz Klonowski Date: Tue, 6 Apr 2021 13:58:28 +0200 Subject: [PATCH 4/6] Use Promise instead of callback for the Database The Database native module has all the methods returning values used asynchronously, but their results are considered as states on the JS side. To avoid loosing the data the Promise has been used to make the database pull more dynamic. --- .../NativeModules/DatabaseHandler.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/windows/ReactNativeNotes/NativeModules/DatabaseHandler.hpp b/windows/ReactNativeNotes/NativeModules/DatabaseHandler.hpp index a001f4f..ea7ef03 100644 --- a/windows/ReactNativeNotes/NativeModules/DatabaseHandler.hpp +++ b/windows/ReactNativeNotes/NativeModules/DatabaseHandler.hpp @@ -24,21 +24,21 @@ namespace winrt::ReactNativeNotes::implementation } REACT_METHOD( GetNoteTitle, L"getNoteTitle" ); - const winrt::hstring GetNoteTitle( const unsigned int ID ) noexcept + void GetNoteTitle( const int index, React::ReactPromise&& result ) noexcept { - return winrt::to_hstring(data->Read( ID ).Title()); + result.Resolve( React::JSValue( data->Read( index ).Title() ) ); } REACT_METHOD( GetNotePost, L"getNotePost" ); - const winrt::hstring GetNotePost( const unsigned int ID ) noexcept + const winrt::hstring GetNotePost( const int index ) noexcept { - return winrt::to_hstring( data->Read( ID ).Post() ); + return winrt::to_hstring( data->Read( index ).Post() ); } REACT_METHOD( GetNoteShortPost, L"getNoteShortPost" ); - const winrt::hstring GetNoteShortPost( const unsigned int ID ) noexcept + void GetNoteShortPost( const int index, React::ReactPromise&& result ) noexcept { - return winrt::to_hstring( data->Read( ID ).ShortPost() ); + result.Resolve( React::JSValue( data->Read( index ).ShortPost() ) ); } REACT_METHOD( GetNumberOfNotes, L"getNumberOfNotes" ); From 918930154c34c5cbc1a83ab45f244f90aab6c07c Mon Sep 17 00:00:00 2001 From: Bartosz Klonowski Date: Tue, 6 Apr 2021 14:05:14 +0200 Subject: [PATCH 5/6] Pull title and short message when creating note widget --- src/Widgets/NoteWidget.js | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/Widgets/NoteWidget.js b/src/Widgets/NoteWidget.js index 54e9ace..4d7ed6c 100644 --- a/src/Widgets/NoteWidget.js +++ b/src/Widgets/NoteWidget.js @@ -11,6 +11,7 @@ import { TouchableHighlight, View, NativeModules, + Alert, } from 'react-native'; @@ -20,6 +21,8 @@ class NoteWidget extends React.Component { this.state = { width: props.width, ID: Number(props.ID), + title: "", + shortMessage: "", } }; @@ -27,6 +30,32 @@ class NoteWidget extends React.Component { NativeModules.NoteWidgetClickHandler.openWidget(this.state.ID); }; + componentDidMount(){ + this.getNoteTitle(); + this.getNoteShortMessage(); + }; + + setTitle = (newTitle) => { + this.setState({title: newTitle}); + }; + + setMessage = (message) => { + this.setState({shortMessage: message}); + }; + + getNoteTitle = () => { + NativeModules.Database.getNoteTitle(this.state.ID) + .then(result => this.setTitle(result)) + .catch(error => Alert.alert("ERROR!", `${error}`)); + }; + + getNoteShortMessage = () => { + NativeModules.Database.getNoteShortPost(this.state.ID) + .then(result => this.setMessage(result)) + .catch(error => Alert.alert("ERROR!", `${error}`)); + }; + + render() { return( @@ -35,7 +64,9 @@ class NoteWidget extends React.Component { {this.state.ID} - Header + + {this.state.title} + @@ -43,10 +74,8 @@ class NoteWidget extends React.Component { - This is the single widget - {'\n'}With the text written here only for the presentation purpose. + {this.state.shortMessage} - This note has the ID: {this.state.ID} From e82a4afd00836e4658d09c0b7b1fdc7a81a505bb Mon Sep 17 00:00:00 2001 From: Bartosz Klonowski Date: Tue, 6 Apr 2021 14:41:32 +0200 Subject: [PATCH 6/6] Use Hooks in NoteWidget --- src/Widgets/NoteWidget.js | 89 ++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 52 deletions(-) diff --git a/src/Widgets/NoteWidget.js b/src/Widgets/NoteWidget.js index 4d7ed6c..35806a3 100644 --- a/src/Widgets/NoteWidget.js +++ b/src/Widgets/NoteWidget.js @@ -3,7 +3,7 @@ * @flow strict-local */ -import React from 'react'; +import React, {useState, useEffect} from 'react'; import { AppRegistry, StyleSheet, @@ -15,76 +15,62 @@ import { } from 'react-native'; -class NoteWidget extends React.Component { - constructor(props) { - super(props); - this.state = { - width: props.width, - ID: Number(props.ID), - title: "", - shortMessage: "", - } - }; +export default function NoteWidget(props){ + const {width, ID} = props; - enterNote = () => { - NativeModules.NoteWidgetClickHandler.openWidget(this.state.ID); - }; + const [title, setTitle] = useState(""); + const [shortMessage, setShortMessage] = useState(""); - componentDidMount(){ - this.getNoteTitle(); - this.getNoteShortMessage(); - }; + useEffect(() => { + getNoteTitle(); + getNoteShortMessage(); + }, []); - setTitle = (newTitle) => { - this.setState({title: newTitle}); + const enterNote = () => { + NativeModules.NoteWidgetClickHandler.openWidget(ID); }; - setMessage = (message) => { - this.setState({shortMessage: message}); - }; - getNoteTitle = () => { - NativeModules.Database.getNoteTitle(this.state.ID) - .then(result => this.setTitle(result)) + const getNoteTitle = () => { + NativeModules.Database.getNoteTitle(ID) + .then(result => setTitle(result)) .catch(error => Alert.alert("ERROR!", `${error}`)); }; - getNoteShortMessage = () => { - NativeModules.Database.getNoteShortPost(this.state.ID) - .then(result => this.setMessage(result)) + const getNoteShortMessage = () => { + NativeModules.Database.getNoteShortPost(ID) + .then(result => setShortMessage(result)) .catch(error => Alert.alert("ERROR!", `${error}`)); }; + return( + + - render() { - return( - - - - - {this.state.ID} - - - {this.state.title} - - - - - - - - - {this.state.shortMessage} + + {ID} + + + {title} + + + + + + {shortMessage} + - - ); - } + + + + ); }; + const styles = StyleSheet.create({ noteWidget: { borderColor: "grey", @@ -124,4 +110,3 @@ const styles = StyleSheet.create({ AppRegistry.registerComponent("NoteWidget", () => NoteWidget); -export default NoteWidget;