Cordova

Cordova

Apache Cordova is a framework that allows developers to create cross-platform mobile applications using web technologies like HTML, JavaScript, and CSS.
Bongani  Ngema

Bongani Ngema

1676350200

Cordova-plugin-firebase: Cordova Plugin for Google Firebase

Cordova-plugin-firebase

This plugin brings push notifications, analytics, event tracking, crash reporting and more from Google Firebase to your Cordova project! Android and iOS supported.

Supported Cordova Versions

  • cordova: >= 6
  • cordova-android: >= 6.4
  • cordova-ios: >= 4

Installation

Install the plugin by adding it to your project's config.xml:

<plugin name="cordova-plugin-firebase" spec="^2.0.0" />

or by running:

cordova plugin add cordova-plugin-firebase --save

Guides

Great installation and setup guide by Medium.com - https://medium.com/@felipepucinelli/how-to-add-push...

Setup

Download your Firebase configuration files, GoogleService-Info.plist for iOS and google-services.json for android, and place them in the root folder of your cordova project. Check out this firebase article for details on how to download the files.

- My Project/
    platforms/
    plugins/
    www/
    config.xml
    google-services.json       <--
    GoogleService-Info.plist   <--
    ...

IMPORTANT NOTES

  • This plugin uses a hook (after prepare) that copies the configuration files to the right place, namely platforms/ios/\<My Project\>/Resources for ios and platforms/android for android.
  • Firebase SDK requires the configuration files to be present and valid, otherwise your app will crash on boot or Firebase features won't work.

PhoneGap Build

Hooks do not work with PhoneGap Build. This means you will have to manually make sure the configuration files are included. One way to do that is to make a private fork of this plugin and replace the placeholder config files (see src/ios and src/android) with your actual ones, as well as hard coding your app id and api key in plugin.xml.

Google Play Services

Your build may fail if you are installing multiple plugins that use Google Play Services. This is caused by the plugins installing different versions of the Google Play Services library. This can be resolved by installing cordova-android-play-services-gradle-release.

If your build is still failing, you can try installing cordova-android-firebase-gradle-release. For more info, read the following comment about locking down the specific versions for play services and firebase. It is suggested to use + instead of 15.+ to ensure the correct versions are used.

Google Tag Manager

Checkout our guide for info on setting up Google Tag Manager.

Configuring Notifications

Checkout our guide for info on configuring notification icons and colors.

API

See the full API available for this plugin.

Download Details:

Author: Arnesson
Source Code: https://github.com/arnesson/cordova-plugin-firebase 
License: MIT license

#firebase #cordova #plugin #notifications 

Cordova-plugin-firebase: Cordova Plugin for Google Firebase
Bongani  Ngema

Bongani Ngema

1671167280

Ionic vs. Cordova vs. React Native

JavaScript frameworks based on React can help you build a fast, reliable mobile app, but it’s not always easy to determine which framework is best for your project. Choosing the wrong framework can result in an app with slow and redundant code. JavaScript expert Sean Wang builds the same natural language processing mobile application using Cordova, Ionic, and React Native, then discusses the advantages and limitations of each.

In the approximately 15 years since Apple released the first iPhone, the software development landscape has changed dramatically. As smartphones gain widespread adoption and continue to grow in unique capabilities, users increasingly prefer to access software services through mobile devices rather than desktops or laptops. Smartphones offer features such as geolocation, biometric authentication, and motion sensing, many of which desktop platforms are only now starting to copy. In some demographics, a smartphone or a similar mobile device is the primary means of software consumption, bypassing computers altogether.

Companies have noticed this shift and reinforced it in major ways. Mobile apps are no longer an afterthought. Applications ranging from Robinhood, a financial brokerage company, to Instagram, a social media company, to Uber, a ride-hailing company, are adopting a mobile-first development strategy. If there is a desktop application, it is often offered as a complement to the mobile app, rather than the primary focus.

For full-stack developers, adapting to these shifting trends is crucial. Fortunately, there are many mature and well-supported technologies available to help web developers apply their skills to mobile development. Today, we will explore three such technologies: Cordova, Ionic, and React Native. We will be using React.js, one of the most popular frameworks for front-end web development, as our core development technology. While we will be focusing on developing an iPhone application, these are cross-platform technologies and will be cross-compilable to the Android platform.

What We Will Build Today

We will build an application that uses Natural Language Processing (NLP) to process and curate Twitter feeds. The application will allow the user to select a set of Twitter handles, pull the most recent updates using a Twitter API, and categorize the tweets based on sentiment and topic. The user will then be able to view the tweets based on sentiment or topic.

Back End

Before we build the front end, we will want to build the back end. We will keep the back end simple for now - we’ll use basic, off-the-shelf sentiment analysis and part-of-speech tagging, along with a little bit of data cleaning to deal with dataset-specific problems. We will use an open-source NLP library called TextBlob and serve the result over Flask.

Sentiment Analysis, Part-of-speech Tagging, and NLP: A Quick Primer

If you have not worked with natural language analysis applications before, these terms may be very foreign to you. NLP is an umbrella term for technologies that analyze and process natural human language data. While this is a broad topic, there are many challenges that are common to all technologies that tackle this area. For example, human language, unlike programming language or numerical data, tends to be loosely structured due to the permissive nature of human language grammar. Additionally, human language tends to be extremely contextual, and a phrase uttered or written in one context may not translate to another context. Finally, structure and context aside, language is extremely complex. Words further down in a paragraph could change the meaning of a sentence at the beginning of the paragraph. Vocabulary can be invented, redefined, or changed. All of these complexities make data analysis techniques difficult to cross-apply.

Sentiment Analysis is a subfield of NLP that focuses on understanding the emotionality of a natural language passage. While human emotion is inherently subjective, and therefore difficult to pin down technologically, sentiment analysis is a subfield that has immense commercial promise. Some applications of sentiment analysis include classifying product reviews to identify positive and negative assessment of various features, detecting the mood of an email or a speech and grouping song lyrics by mood. If you’re looking for a more in-depth explanation of Sentiment Analysis, you can read my article on building a Sentiment Analysis-based application here.

Part-of-speech tagging, or POS tagging, is a very different subfield. The goal of POS tagging is to identify the part of speech of a given word in a sentence using grammatical and contextual information. Identifying this relationship is a much more difficult task than initially meets the eye - a word can have very different parts of speech based on the context and the structure of the sentence, and the rules aren’t always clear even to humans. Fortunately, many off-the-shelf models today provide powerful and versatile models integrated with most major programming languages. If you would like to learn more, you can read my article on POS tagging here.

Flask, TextBlob, and Tweepy

For our NLP back end, we will use Flask, TextBlob, and Tweepy. We will use Flask to build a small, lightweight server, TextBlob to run our natural language processing, and Tweepy to get tweets from the Twitter API. Before you start coding, you will also want to get a developer key from Twitter so you can retrieve tweets.

We can write a much more sophisticated back end and use more complex NLP technologies, but for our purposes today, we will keep the back end as simple as possible.

Back-end Code

Now, we’re ready to start coding. Fire up your favorite Python editor and terminal, and let’s get cracking!

First, we will want to install the requisite packages.

pip install flask flask-cors textblob tweepy
python -m textblob.download_corpora

Now, let’s write the code for our functionality.

Open up a new Python script, call it server.py, and import the requisite libraries:

import tweepy

from textblob import TextBlob
from collections import defaultdict

Let’s now write some helper functions:

# simple, average a list of numbers with a guard clause to avoid division by zero
def mean(lst):
    return sum(lst)/len(lst) if len(lst) > 0 else 0

# call the textblob sentiment analysis API and noun phrases API and return it as a dict
def get_sentiment_and_np(sentence):
    blob = TextBlob(sentence)
    return{
        'sentiment': mean([s.sentiment.polarity for s in blob.sentences if s.sentiment.polarity != 0.0]),
        'noun_phrases': list(blob.noun_phrases)
    }

# use the tweepy API to get the last 50 posts from a user’s timeline
# We will want to get the full text if the text is truncated, and we will also remove retweets since they’re not tweets by that particular account.
def get_tweets(handle):
    auth = tweepy.OAuthHandler('YOUR_DEVELOPER_KEY')
    auth.set_access_token('YOUR_DEVELOPER_SECRET_KEY')
    api = tweepy.API(auth)
    tl = api.user_timeline(handle, count=50)
    tweets = []
    for tl_item in tl:
        if 'retweeted_status' in tl_item._json:
            Continue # this is a retweet
        if tl_item._json['truncated']:
            status = api.get_status(tl_item._json['id'], tweet_mode='extended') # get full text
            tweets.append(status._json['full_text'])
        else:
            tweets.append(tl_item._json['text'])
    return tweets

# http and https are sometimes recognized as noun phrases, so we filter it out.
# We also try to skip noun phrases with very short words to avoid certain false positives
# If this were a commercial app, we would want a more sophisticated filtering strategy.
def good_noun_phrase(noun_phrase):
    noun_phrase_list = noun_phrase.split(' ')
    for np in noun_phrase_list:
        if np in {'http', 'https'} or len(np) < 3:
            return False
    return True

Now that we have the helper functions written, we can put everything together with a couple of simple functions:

# reshapes the tagged tweets into dictionaries that can be easily consumed by the front-end app
def group_tweets(processed_tweets):
    # Sort it by sentiment
    sentiment_sorted = sorted(processed_tweets, key=lambda x: x['data']['sentiment'])

    # collect tweets by noun phrases. One tweet can be present in the list of more than one noun phrase, obviously.
    tweets_by_np = defaultdict(list)

    for pt in processed_tweets:
        for np in pt['data']['noun_phrases']:
            tweets_by_np[np].append(pt)
    grouped_by_np = {np.title(): tweets for np, tweets in tweets_by_np.items() if len(tweets) > 1 and good_noun_phrase(np)}
    return sentiment_sorted, grouped_by_np

# download, filter, and analyze the tweets
def download_analyze_tweets(accounts):
    processed_tweets = []
    for account in accounts:
        for tweet in get_tweets(account):
            processed_tweet = ' '.join([i for i in tweet.split(' ') if not i.startswith('@')])
            res = get_sentiment_and_np(processed_tweet)
            processed_tweets.append({
                'account': account,
                'tweet': tweet,
                'data': res
            })

    sentiment_sorted, grouped_by_np = group_tweets(processed_tweets)
    return processed_tweets, sentiment_sorted, grouped_by_np

You can now run the function download_analyze_tweets on a list of handles that you want to follow, and you should see the results.

I ran the following code:

if __name__ == '__main__':
    accounts = ['@spacex', '@nasa']
    processed_tweets, sentiment_sorted, grouped_by_np = download_analyze_tweets(accounts)
    print(processed_tweets)
    print(sentiment_sorted)
    print(grouped_by_np)

Executing this produced the following results. The results are obviously time-dependent, so if you see something similar, you’re on the right track.

[{'account': '@spacex', 'tweet': 'Falcon 9…
[{'account': '@nasa', 'tweet': 'Our Mars rove…
{'Falcon': [{'account': '@spacex', 'tweet': 'Falc….

Now we can build out the Flask server, which is quite simple. Create an empty file called server.py and write the following code:

from flask import Flask, request, jsonify
from twitter import download_analyze_tweets
from flask_cors import CORS

app = Flask(__name__)

CORS(app)

@app.route('/get_tweets', methods=['POST'])

def get_tweets():
    accounts = request.json['accounts']
    processed_tweets, sentiment_sorted, grouped_by_np = download_analyze_tweets(accounts)
    return jsonify({
        'processedTweets': processed_tweets,
        'sentimentSorted': sentiment_sorted,
        'groupedByNp': grouped_by_np
    })

if __name__ == '__main__':
    app.run(debug=True)

Run the server, and you should now be able to send a post request to the server using an HTTP client of your choice. Pass in {accounts: [“@NASA”, “@SpaceX”]} as a json argument, and you should see the API return something similar to what was returned in the Twitter analysis code.

Now that we have a server, we are ready to code the front end. Because of a small nuance in networking over a phone emulator, I recommend that you deploy your API somewhere. Otherwise, you will want to detect whether your app is running on an emulator and send requests to <Your Computer IP>:5000 instead of localhost:5000 when it is in an emulator. If you deploy the code, you can simply issue the request to that URL.

There are many options to deploy the server. For a free, simple debug server with minimal setup required, I recommend something like PythonAnywhere, which should be able to run this server out of the box.

Now that we have coded the back-end server, let’s look at the front end. We’ll start with one of the most convenient options for a web developer: Cordova.

Apache Cordova Implementation

Cordova Primer

Apache Cordova is a software technology to help web developers target mobile platforms. By taking advantage of web browser capabilities implemented on smartphone platforms, Cordova wraps web application code into a native application container to create an application. Cordova isn’t simply a fancy web browser, however. Through the Cordova API, web developers can access many smartphone-specific features such as offline support, location services, and on-device camera.

For our application, we will write an application using React.js as the JS framework and React-Bootstrap as the CSS framework. Because Bootstrap is a responsive CSS framework, it already has support for running on smaller screens. Once the application is written, we will compile it into a web application using Cordova.

Configuring the App

We will start by doing something unique to set up the Cordova React app. In a Medium article, developer Shubham Patil explains what we’re doing. Essentially, we’re setting up a React development environment using the React CLI, and then a Cordova development environment using the Cordova CLI, before finally merging the two.

To start, run the following two commands in your code folder:

cordova create TwitterCurationCordova

create-react-app twittercurationreact

Once the setup is done, we will want to move the contents of the React app’s public and src folder to the Cordova app. Then, in the package.json, copy over the scripts, browser list, and dependencies from the React project. Also add "homepage": "./" at the root of the package.json to enable compatibility with Cordova.

Once the package.json is merged, we will want to change the public/index.html file to work with Cordova. Open up the file and copy the meta tags from www/index.html as well as the script at the end of the body tag when Cordova.js is loaded.

Next, change the src/index.js file to detect if it’s running on Cordova. If it’s running on Cordova, we will want to run the render code within the deviceready event handler. If it’s running in a regular browser, just render right away.

const renderReactDom = () => {
  ReactDOM.render(
    <React.StrictMode>
      <App />
    </React.StrictMode>,
    document.getElementById('root')
  );
}

if (window.cordova) {
  document.addEventListener('deviceready', () => {
    renderReactDom();
  }, false);
} else {
  renderReactDom();
}

Finally, we need to set up our deployment pipeline. Add the below definition into the config.xml file:

<hook type="before_prepare" src="hooks/prebuild.js" />

And put the following script into prebuild.js:

const path = require('path');
const { exec } = require('child_process');
const fs = require('fs');
const rimraf = require('rimraf');

function renameOutputFolder(buildFolderPath, outputFolderPath) {
    return new Promise((resolve, reject) => {
        fs.rename(buildFolderPath, outputFolderPath, (err) => {
            if (err) {
                reject(err);
            } else {
                resolve('Successfully built!');
            }
        });
    });
}

function execPostReactBuild(buildFolderPath, outputFolderPath) {
    return new Promise((resolve, reject) => {
        if (fs.existsSync(buildFolderPath)) {
            if (fs.existsSync(outputFolderPath)) {
                rimraf(outputFolderPath, (err) => {
                    if (err) {
                        reject(err);
                        return;
                    }
                    renameOutputFolder(buildFolderPath, outputFolderPath)
                        .then(val => resolve(val))
                        .catch(e => reject(e));
                });
            } else {
                renameOutputFolder(buildFolderPath, outputFolderPath)
                    .then(val => resolve(val))
                    .catch(e => reject(e));
            }
        } else {
            reject(new Error('build folder does not exist'));
        }
    });
}

module.exports = () => {
    const projectPath = path.resolve(process.cwd(), './node_modules/.bin/react-scripts');
    return new Promise((resolve, reject) => {
        exec(`${projectPath} build`,
            (error) => {
                if (error) {
                    console.error(error);
                    reject(error);
                    return;
                }
                execPostReactBuild(path.resolve(__dirname, '../build/'), path.join(__dirname, '../www/'))
                    .then((s) => {
                        console.log(s);
                        resolve(s);
                    })
                    .catch((e) => {
                     console.error(e);
                        reject(e);
                    });
            });
    });
};

This executes the React build and puts the build folder into the appropriate place before the Cordova build starts, thus automating the deployment process.

Now, we can try running our app. Run the following in the command line:

npm install rimraf
npm install
npm run start

You should see the React app set up and running in the browser. Add Cordova now:

cordova platform add iOS

cordova run iOS

And you should see the React app running in the emulator.

Router and Packages Setup

To set up some of the infrastructure that we need to build the app, let’s start by installing the requisite packages:

npm install react-bootstrap react-router react-router-dom

We will now set up the routing, and while doing so, we will also set up a simple global state object that will be shared by all the components. In a production application, we will want to use a state management system like Redux or MobX, but we will keep it simple for now. Go to App.js and configure the route thus:

import {
  BrowserRouter as Router,
  Redirect,
  Route,
} from "react-router-dom";

function App() {
  const [curatedTweets, setCuratedTweets] = useState();
  return <Router>
      <Route path="/" exact render={() => <Input setCuratedTweets={setCuratedTweets} />} />
      <Route path="/display" render={() => <Display curatedTweets={curatedTweets} />} />
      <Route path="*" exact render={() => <Redirect to="/" />} />
  </Router>
}

With this route definition, we have introduced two routes that we will need to implement: Input and Display. Notice that the curatedTweets variable is being passed to Display, and the setCuratedTweets variable is being passed to Input. This means the input component will be able to call the function to set the curatedTweets variable, and Display will get the variable to display.

To start coding the components, let’s create a folder under /src called /src/components. Under /src/components, create another folder called /src/components/input and two files underneath: input.js and input.css. Do the same for the Display component - create /src/components/display and underneath: display.js and display.css.

Under those, let’s create stub components, like so:

import React from ‘react’;
import ‘input.css’

const Input = () => <div>Input</div>;
export default Input

And the same for Display:

import React from ‘react’;
import display.css’

const Display = () => <div>Display</div>;
export default Display

With that, our wireframing is complete and the app should run. Let us now code up the Input page.

Input Page

Big-picture Plan

Before we write the code, let’s think about what we want our Input page to do. Obviously, we will want a way for the users to input and edit the Twitter handles that they want to pull from. We also want the users to be able to indicate that they’re done. When the users indicate they are done, we will want to pull the curated tweets from our Python curation API and finally navigate to the Display component.

Now that we know what we want our component to do, we are ready to code.

Setting Up the File

Let’s start by importing React Router library’s withRouter to get access to navigation functionality, the React Bootstrap Components we need, like so:

import React, {useState} from 'react';
import {withRouter} from 'react-router-dom';
import {ListGroup, Button, Form, Container, Row, Col} from 'react-bootstrap';
import './input.css';

Now, let’s define the stub function for Input. We know that Input gets the setCuratedTweets function, and we also want to give it the ability to navigate to the display route after it sets the curated tweets from our Python API. Therefore, we will want to take from the props setCuratedTweets and history (for navigation).

const Input = ({setCuratedTweets, history}) => {
    return <div>Input</div>
}

To give it the history API access, we will wrap it with withRouter in the export statement at the end of the file:

export default withRouter(Input);

Data Containers

Let’s set up the data containers using React Hooks. We already imported the useState hook so we can add the following code to the Input component’s body:

const [handles, setHandles] = useState([]);
const [handleText, setHandleText] = useState(‘’);

This creates the container and modifiers for handles, which will hold the list of handles that the user wishes to pull from, and the handleText, which will hold the content of the textbox that the user uses to input the handle.

Now, let’s code up the UI components.

UI Components

The UI components will be fairly simple. We will have one Bootstrap row that contains the input textbox along with two buttons, one to add the current input box content to the list of handles, and one to pull from the API. We will have another Bootstrap row that displays the list of handles that the user wishes to pull using the Bootstrap list group. In code, it looks like so:

return (
    <Container className="tl-container">
        <Row>
            <Col>
                <Form.Control type="text" value={handleText} onChange={changeHandler} placeholder="Enter handle to pull" />
            </Col>
        </Row>
        <Row className='input-row'>
            <Col>
                <Button variant="primary" onClick={getPull}>Pull</Button>
                {' '}
                <Button variant="success" onClick={onAddClicked}>Add</Button>
            </Col>
        </Row>
        <Row>
            <Col>
                <ListGroup className="handles-lg">
                    {handles.map((x, i) => <ListGroup.Item key={i}>
                        {x}
                        <span onClick={groupItemClickedBuilder(i)} className="delete-btn-span">
                        <Button variant="danger" size="sm">
                        delete
                        </Button>
                        </span>
                    </ListGroup.Item>)}
                </ListGroup>
            </Col>
        </Row>
    </Container>
); 

In addition to the UI component, we will want to implement the three UI event handlers that handle data changes. The getPull event handler, which calls the API, will be implemented in the next section.

// set the handleText to current event value
const textChangeHandler = (e) => {
    e.preventDefault();
    setHandleText(e.target.value);
}

// Add handleText to handles, and then empty the handleText
const onAddClicked = (e) => {
    e.preventDefault();
    const newHandles = [...handles, handleText];
    setHandles(newHandles);
    setHandleText('');
}

// Remove the clicked handle from the list
const groupItemClickedBuilder = (idx) => (e) => {
    e.preventDefault();
    const newHandles = [...handles];
    newHandles.splice(idx, 1);
    setHandles(newHandles);
}

Now, we’re ready to implement the API call.

API Call

For the API call, we want to take the handles that we want to pull, send that over to the Python API in a POST request, and put the resulting JSON result into the curatedTweets variable. Then, if everything goes well, we want to programmatically navigate to the /display route. Otherwise, we will log the error to the console so we can debug more easily.

In code mode, it looks like this:

const pullAPI = (e) => {
    e.preventDefault();
    fetch('http://prismatic.pythonanywhere.com/get_tweets', {
        method: 'POST',
            mode: 'cors',
            headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
            },
            body: JSON.stringify({
            accounts: handles
            })
        }).then(r=>r.json()).then(j => {
        setCuratedTweets(j);
            history.push('/display');
        })
    .catch(e => {
        console.log(e);
        })
}

And with that, we should be good to go. Feel free to run the app, add a couple of handles, and send a request over to the API.

Now, we’re ready to code the sentiment page.

Sentiment Sorted Mode

Because the Python API already sorts the tweets by sentiment, once we have the result from the Python API, the sentiment page is actually not too difficult.

Big-picture Plan

We will want a list interface to show the tweets. We will also want a couple of navigational components to switch to topic grouping mode and to go back to the Input page.

To start, let’s define the SentimentDisplay mode sub-component in the display.js file.

SentimentDisplay Component

The SentimentDisplay will take the curatedTweets object and display the sentiment-sorted tweets in a list. With the help of React-Bootstrap, the component is quite simple:

const SentimentDisplay = ({curatedTweets}) => {
    return <ListGroup>
      {curatedTweets.sentimentSorted.map((x, i) =>
            <ListGroup.Item key={i}>
                <div className="account-div">{x.account}:</div>
                <span className="tweet-span">{x.tweet}</span>
                <span className="sentiments-span">({x.data.sentiment.toPrecision(2)})</span>
            </ListGroup.Item>
        )}
    </ListGroup>
}

While we’re at it, let’s also add some styling. Put the following into display.css and import it:

 .account-div {
    font-size: 12px;
    font-weight: 600;

}

.tweet-span {
    font-size: 11px;
    font-weight: 500;
}

.sentiments-span {
    font-size: 10px;
}

.tl-container {
    margin-top: 10px;
}

.disp-row {
    margin-top: 5px;
}

We can now show the SentimentDisplay component. Change the Display function like so:

const Display = ({curatedTweets}) => {
    return <SentimentDisplay curatedTweets={curatedTweets} />
};

Let’s also take this opportunity to code up the navigational components. We will want two buttons - the “Back to edit” button and the Topic Group Mode.

We can implement these buttons in a separate Bootstrap row right above the SentimentDisplay component, like so:

Return <Container className="tl-container">
    <Row>
        <Col>
            <Link to="/"><Button variant='primary'>Back</Button></Link>
            {' '}
           <Button variant='success'>View by Topic</Button>
        </Col>
    </Row>
    <Row className="disp-row">
        <Col>
            <SentimentDisplay curatedTweets={curatedTweets} />
        </Col>
    </Row>
</Container>

Run the app and pull the tweets from a couple of handles. Looks pretty nifty!

Topic Grouping Mode

Now, we want to implement the Topic Grouping Mode. It’s a bit more complex than the SentimentDisplay, but again, some very handy Bootstrap components help us out immensely.

Big-picture Plan

We will get all the noun phrases and display them as an accordion list. We will then render the tweets containing the noun phrases once the accordion list is expanded.

Implementing Switching to Topic Grouping Mode

First, let’s implement logic to switch from Sentiment Mode to Topic Grouping Mode. Let’s start by creating the stub component first:

const TopicDisplay = () => {
    return <div>Topic Display</div>
}

And set some logic to create a mode to display it. In the main Display Component, add the following lines to create the logic for which component gets displayed.

// controls the display mode. Remember to import {useState} from ‘react’
const [displayType, setDisplayType] = useState('Sentiment');

// Switch the Display Mode
const toggleDisplayType = () => {
    setDisplayType(displayType === 'Sentiment' ? 'Topic': 'Sentiment');
}

// determines the text on the mode switch button
const switchStr = displayType === 'Sentiment'? 'View by Topic': 'View by Sentiment'

And change the JSX to the following to add the logic:

Return <Container className="tl-container">
    <Row>
        <Col>
            <Link to="/"><Button variant='primary'>Back</Button></Link>
            {' '}
            <Button variant='success' onClick={toggleDisplayType}>{switchStr}</Button>
        </Col>
    </Row>
    <Row className="disp-row">
        <Col>
                {
                    displayType === 'Sentiment'?
                    <SentimentDisplay curatedTweets={curatedTweets} />:
                    <TopicDisplay curatedTweets={curatedTweets} />
                }
        </Col>
    </Row>
</Container>

Now, you should see the Topic Group Display stub when you toggle.

The TopicDisplay Component

Now, we are ready to code the TopicDisplay component. As discussed before, it will leverage the Bootstrap Accordion List. The implementation is actually fairly simple:

const TopicDisplay = ({curatedTweets}) => {
    return <Accordion>
        {Object.keys(curatedTweets.groupedByNp).map((x, i) =>
            <Card key={i}>
                <Card.Header>
                    <Accordion.Toggle as={Button} variant="link" eventKey={i}>
                        {x} ({curatedTweets.groupedByNp[x].length})
                    </Accordion.Toggle>
                </Card.Header>
                <Accordion.Collapse eventKey={i}>
                    <Card.Body>
                        <ListGroup>
                            {curatedTweets.groupedByNp[x].map((y, i2) =>
                                <ListGroup.Item key={i2}>
                                    <div className="account-div">{y.account}:</div>
                                    <span className="tweet-span">{y.tweet}</span>
                                 <span className="sentiments-span">({y.data.sentiment.toPrecision(2)})</span>
                                </ListGroup.Item>
                            )}
                        </ListGroup>
                    </Card.Body>
                </Accordion.Collapse>
            </Card>
        )}
  </Accordion>
}

Run the app, and you should see the Topic Display.

Now the app is done, and we are ready to build the app for the emulator.

Running the App in the Emulator

Cordova makes it very easy to run the app in the emulator. Simply run:

cordova platform add ios # if you haven’t done so already
cordova run ios

And you should see the app in the emulator. Because Bootstrap is a responsive web app, the web app adapts to the width of an iPhone, and everything looks quite nice.

With the Cordova app done, let’s now look at the Ionic implementation.

Ionic-React Implementation

Ionic Primer

Ionic is a web component library and CLI toolkit that makes building hybrid applications easier. Originally, Ionic was built on top of AngularJS and Cordova, but they have since released their components in React.js and began supporting Capacitor, a platform similar to Cordova. What sets Ionic apart is that even though you are using web components, the components feel very similar to a native mobile interface. Additionally, the look and feel of the Ionic components automatically adapt to the operating system it runs on, which again helps the application look and feel more native and natural. Finally, while this is outside of the scope of our article, Ionic also provides several build tools that make deploying your application a bit easier.

For our application, we will be using Ionic’s React components to build the UI while leveraging some of the JavaScript logic we built during the Cordova section.

Configuring the App

First, we will want to install the Ionic tools. So let’s run the following:

npm install -g @Ionic/cli native-run cordova-res

And after the install is done, let’s go to the project folder. Now, we use the Ionic CLI to create our new project folder:

ionic start twitter-curation-Ionic blank --type=react --capacitor

Watch the magic happen, and now go into the folder with:

cd twitter-curation-Ionic

And run the blank app with:

ionic serve

Our app is thus set up and ready to go. Let’s define some routes.

Before we move on, you will notice that Ionic started the project using TypeScript. While I don’t go out of my way to use TypeScript, it has some very nice features, and we will be using it for this implementation.

Router Setup

For this implementation, we will use three routes - input, sentimentDisplay, and topicDisplay. We do this because we want to take advantage of the transition and navigation features provided by Ionic and because we’re using Ionic components, and accordion lists do not come prepackaged with Ionic. We can implement our own, of course, but for this tutorial, we will stay with the provided Ionic components.

If you navigate to the App.tsx, you should see the basic routes already defined.

Input Page

Big-picture Plan

We’ll be using a lot of the similar logic and code as the Bootstrap implementation, with a few key differences. First, we will use TypeScript, which means we will have type annotations for our code, which you will see in the next section. Second, we will be using Ionic components, which are very similar in style to Bootstrap but will be OS-sensitive in its styling. Lastly, we will be navigating dynamically using the history API like in the Bootstrap version but accessing the history slightly differently due to the Ionic Router implementation.

Setting Up

Let’s begin by setting up the input component with a stub component. Create a folder under pages named input and create under that a file named Input.tsx. Inside that file, put the following code to create a React component. Notice that because we’re using TypeScript, it’s a little bit different.

import React, {useState} from 'react';

const Input : React.FC = () => {
    return <div>Input</div>;
}

export default Input;

And change the component in App.tsx to:

const App: React.FC = () => (
  <IonApp>
    <IonReactRouter>
      <IonRouterOutlet>
        <Route path="/input" component={Input} exact={true} />
        <Route exact path="/" render={() => <Redirect to="/input" />} />
      </IonRouterOutlet>
    </IonReactRouter>
  </IonApp>
);

Now, when you refresh the app, you should see the Input stub component.

Data Containers

Let’s create the data containers now. We want the containers for inputted Twitter handles as well as the current contents of the input box. Because we’re using TypeScript, we’ll need to add the type annotations to our useState invocation in the component function:

const Input : React.FC = () => {
    const [text, setText] = useState<string>('');
    const [accounts, setAccounts] = useState<Array<string>>([]);
    return <div>Input</div>;
}

We will also want a data container to hold the return values from the API. Because the content of that needs to be shared with the other routes, we define them at the App.tsx level. Import useState from React in the App.tsx file and change the app container function to the below:

const App: React.FC = () => {
  const [curatedTweets, setCuratedTweets] = useState<CuratedTweets>({} as CuratedTweets);
  return (
  <IonApp>
    <IonReactRouter>
      <IonRouterOutlet>
        <Route path="/input" component={Input} exact={true} />
        <Route exact path="/" render={() => <Redirect to="/input" />} />
      </IonRouterOutlet>
    </IonReactRouter>
  </IonApp>
  );
}

At this point, if you are using an editor with syntax highlighting like Visual Studio Code, you should see the CuratedTweets light up. This is because the file does not know what the CuratedTweets interface looks like. Let’s define that now. Create a folder under src called interfaces and create a file inside it called CuratedTweets.tsx. In the file, define the CuratedTweets interface as follows:

 interface TweetRecordData {
    noun_phrases: Array<string>,
    sentiment: number
}

export interface TweetRecord {
    account: string,
    data: TweetRecordData,
    tweet: string
}

export default interface CuratedTweets {
    groupedByNp: Record<string, Array<TweetRecord>>,
    processedTweets: Array<TweetRecord>,
    sentimentSorted: Array<TweetRecord>
}

Now the app knows about the structure of the API return data. Import the CuratedTweets interface in App.tsx. You should see the App.tsx compile with no problem now.

We need to do a couple more things here. We need to pass the setCuratedTweets function into the Input component and make the Input component aware of this function.

In the App.tsx, modify the Input route like so:

<Route path="/input" render={() => <Input setCuratedTweets={setCuratedTweets}/>} exact={true} />

Now, you should see the editor flag down something else - Input does not know about the new prop being passed to it so we will want to define it in Input.tsx.

First, import the CuratedTweets interface, then define the ContainerProps interface like so:

interface ContainerProps {
    setCuratedTweets: React.Dispatch<React.SetStateAction<CuratedTweets>>
}

And finally, change the Input component definition like so:

const Input : React.FC<ContainerProps> = ({setCuratedTweets}) => {
    const [text, setText] = useState<string>('');
    const [accounts, setAccounts] = useState<Array<string>>([]);
    return <div>Input</div>;
}

We are done defining the data containers, and now, onto building the UI components.

UI Components

For the UI component, we will want to build an input component and a list display component. Ionic provides some simple containers for these.

Let’s start by importing the library components we’ll be using:

import { IonInput, IonItem, IonList, IonButton, IonGrid, IonRow, IonCol } from '@Ionic/react';

Now, we can replace the stub component with the IonInput, wrapped in an IonGrid:

return <IonGrid>
    <IonRow>
        <IonCol>
            <IonInput
              value={text}
              placeholder="Enter accounts to pull from"
              onIonChange={e => setText(e.detail.value!)} />
      </IonCol>
    </IonRow>
</IonGrid>

Notice that the event listener is onIonChange instead of onChange. Otherwise, it should look very familiar.

When you open the app in your browser, it may not look like the Bootstrap app. However, if you set your browser to emulator mode, the UI will make more sense. It will look even better once you deploy it on mobile, so look forward to it.

Now, let’s add some buttons. We will want an “Add to list” button and a “Pull API” button. For that, we can use IonButton. Change the size of the input’s IonCol to 8 and add the following two buttons with columns:

<IonCol size="8">
            <IonInput
              value={text}
              placeholder="Enter accounts to pull from"
              onIonChange={e => setText(e.detail.value!)} />
        </IonCol>
        <IonCol size="2">
            <IonButton style={{float: 'right'}} color="primary" size="small" onClick={onAddClicked}>Add</IonButton>
        </IonCol>
        <IonCol size="2">
           <IonButton style={{float: 'right'}} color="success" size="small" onClick={onPullClicked}>Pull</IonButton>
        </IonCol>

Since we’re writing the buttons, let’s write the event handlers as well.

The handler to add a Twitter handle to the list is simple:

const onAddClicked = () => {
        if (text === undefined || text.length === 0) {
            return;
        }
        const newAccounts: Array<string> = [...accounts, text];
        setAccounts(newAccounts);
        setText('');
    }

We will implement the API call in the next section, so let’s just put a stub function for onPullClicked:

const onPullClicked = () => {}

Now, we need to write the component for displaying the list of handles that has been inputted by the user. For that, we will use IonList, put into a new IonRow:

<IonRow>
    <IonCol>
        <IonList>
            {accounts.map((x:string, i:number) => <IonItem key={i}>
                <IonGrid>
                    <IonRow>
                        <IonCol size="8" style={{paddingTop: '12px'}}>{x}</IonCol>
                        <IonCol><IonButton style={{float: 'right'}} color="danger" size="small" onClick={deleteClickedBuilder(i)}>Delete</IonButton></IonCol>
                    </IonRow>
                </IonGrid>
            </IonItem>)}
        </IonList>
    </IonCol>
</IonRow>

Each list item is displaying the handle and a delete button in its very own IonGrid. For this code to compile, we will want to implement the deleteClickedHandler as well. It should be very familiar from the previous section but with TypeScript annotations.

const deleteClickedBuilder = (idx: number) => () => {
    const newAccounts: Array<string> = [...accounts];
    newAccounts.splice(idx, 1);
    setAccounts(newAccounts);
}

Save this, and you should see the Input page with all the UI components implemented. We can add handles, delete handles, and click the button to invoke the API.

As a final exercise, let’s move the in-line styles to CSS. Create a file in the input folder called input.css and import it in the Input.tsx file. Then, add the following styles:

.input-button {
    float: right;
}

.handle-display {
    padding-top: 12px;
}

Now, add className="input-button” on all of the IonButtons and className=”handle-display” on the handle list item IonCol that is displaying the intended Twitter handle. Save the file, and you should see everything looking quite good.

API Call

The code to pull the API is very familiar from the previous section, with one exception - we have to get access to the history component to be able to dynamically change routes. We will do this using the withHistory hook.

We first import the hook:

import { useHistory } from 'react-router';

And then implement the handler in the input component:

const history = useHistory();

const switchToDisplay = () => {
    history.push('/display');
}

const onPullClicked = () => {
    fetch('http://prismatic.pythonanywhere.com/get_tweets', {
        method: 'POST',
        mode: 'cors',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            accounts
        })
    }).then(r=>r.json()).then(j => {
        setCuratedTweets(j);
        switchToDisplay();
    })
    .catch(e => {
        console.log(e);
    })

}

Adding a Header

Our Input page looks quite nice, but it looks a little bare due to Ionic’s mobile-centric styling. To make the UI look more natural, Ionic provides a header feature that lets us provide a more natural user experience. When running on mobile, the header will also simulate the native OS’s mobile platform, which makes the user experience even more natural.

Change your component import to:

import { IonPage, IonHeader, IonToolbar, IonTitle, IonContent, IonInput, IonItem, IonList, IonButton, IonGrid, IonRow, IonCol } from '@Ionic/react';

And now wrap the UI in an Ionic page with a header, like so:

return <IonPage>
    <IonHeader>
      <IonToolbar>
        <IonTitle>Twitter Curation App</IonTitle>
      </IonToolbar>
    </IonHeader>
    <IonContent>
      <IonHeader collapse="condense">
        <IonToolbar>
        <IonTitle size="large">Twitter Curation App</IonTitle>
        </IonToolbar>
      </IonHeader>
       <IonGrid>
        <IonRow>
            <IonCol size="8">
                <IonInput
                value={text}
                placeholder="Enter accounts to pull from"
                onIonChange={e => setText(e.detail.value!)} />
            </IonCol>
            <IonCol size="2">
                <IonButton className="input-button" color="primary" size="small" onClick={onAddClicked}>Add</IonButton>
            </IonCol>

            <IonCol size="2">
            <IonButton className="input-button" color="success" size="small" onClick={onPullClicked}>Pull</IonButton>
            </IonCol>

        </IonRow>

        <IonRow>
            <IonCol>
                <IonList>
                    {accounts.map((x:string, i:number) => <IonItem key={i}>
                        <IonGrid>
                            <IonRow>
                                <IonCol size="8" className="handle-display">{x}</IonCol>
                                <IonCol><IonButton className="input-button" color="danger" size="small" onClick={deleteClickedBuilder(i)}>Delete</IonButton></IonCol>
                            </IonRow>
                        </IonGrid>
                 </IonItem>)}
                </IonList>
            </IonCol>
        </IonRow>
    </IonGrid>
    </IonContent>
  </IonPage>

Now that looks nice!

Sentiment Sorted Page

Big-picture Plan

The sentiment sorted page will be largely similar to the sentiment sorted page from the Bootstrap page but using TypeScript and Ionic. We will also implement the Topic Display as a separate route to take advantage of Ionic’s navigation features while running on mobile, so we will need to give this page the ability to navigate to the Topic Display route as well.

Route Setup

Let’s begin by creating a new folder called sentimentsorted and a file named SentimentSorted.tsx underneath. Export a stub component like so:

import React from 'react';

const SentimentSorted: React.FC = () => {
    return <div>Sentiment Sorted</div>
}
export default SentimentSorted;

And in the App.tsx, import the component:

import SentimentSorted from './pages/sentimentsorted/SentimentSorted';

And add the route:

<Route path="/display" render={() => <SentimentSorted curatedTweets={curatedTweets} />} />

You will get a TypeScript error saying that SentimentSorted is not expecting the curatedTweets props, so let’s take care of that now in the next section.

UI Components

Let’s begin by defining the container’s props. Much like the input component:

import CuratedTweets from '../../interfaces/CuratedTweets';

interface ContainerProps {
    curatedTweets: CuratedTweets
}

And now, change the stub display:

const SentimentSorted: React.FC<ContainerProps> = ({curatedTweets}) => {
    return <div>Sentiment Sorted</div>
}

And everything should compile.

The display is very simple, it’s just an IonList with display components:

return <IonGrid>
    <IonRow>
        <IonCol>
        <IonList>
            {(curatedTweets.sentimentSorted).map((x, i) =>
            <IonItem key={i}>
                <IonLabel className="ion-text-wrap">
                    <h2>{x.account}:</h2>
                    <h3>{x.tweet}</h3>
                    <p>({x.data.sentiment.toPrecision(2)})</p>
                </IonLabel>
            </IonItem>)}
        </IonList>
        </IonCol>
    </IonRow>
</IonGrid>

If you save and pull some tweets using the input component, you should see the tweets displayed in a list.

Now, let’s add the navigation buttons. Add to the IonGrid:

<IonRow>
    <IonCol>
        <IonButton color='primary' onClick={switchToInput}>Back</IonButton>
        <IonButton color="success" onClick={toggleDisplayType}>{switchStr}</IonButton>
    </IonCol>
</IonRow>

The switchToInput is very easy to implement with the history API:

const switchToInput = () => {
    history.goBack();
}

And ToggleDisplayType should be familiar as well:

const toggleDisplayType = () => {
    setDisplayType(displayType === 'Sentiment' ? 'Topic': 'Sentiment');
}

const switchStr = displayType === 'Sentiment'? 'View by Topic': 'View by Sentiment'

Now we have the SentimentDisplay component implemented. Now, before we implement the Topic Display Page, we need to implement the component that displays all the topics. We will do that in the next section.

Topic Groups Component

Let’s add a topic list display option and display it conditionally. To do that, we need to break out the Sentiment Display list. Rename SentimentDisplay to Display, and let’s break out the sentiment display list:

interface SentimentDisplayProps {
    sentimentSorted: Array<TweetRecord>
}

const SentimentDisplay: React.FC<SentimentDisplayProps> = ({sentimentSorted}) => {
    return <IonList>
        {(sentimentSorted || []).map((x, i) =>
        <IonItem key={i}>
            <IonLabel className="ion-text-wrap">
                <h2>{x.account}:</h2>
                <h3>{x.tweet}</h3>
                <p>({x.data.sentiment.toPrecision(2)})</p>
            </IonLabel>
        </IonItem>)}
    </IonList>
}

Notice how we are using one of the class definitions in the CuratedTweets interface. That’s because these components do not need the entire CuratedTweets object but only a subset. The topic list is very similar:

interface TopicDisplayProps {
    groupedByNP: Record<string, Array<TweetRecord>>
}

const TopicDisplay: React.FC<TopicDisplayProps> = ({groupedByNP}) => {
    return <IonList>
        {Object.keys(groupedByNP || {}).map((x, i) =>
        <IonItem key={i}  routerLink={`/topicDisplay/${encodeURIComponent(x)}`}>
            <IonLabel className="ion-text-wrap">
                <h2>{x} ({groupedByNP[x].length})</h2>
            </IonLabel>
        </IonItem>)}
    </IonList>
}

And now, conditional display is easy to set up in the Display Component:

return (
    <IonGrid>
        <IonRow>
            <IonCol>
                <IonButton color='primary' onClick={switchToInput}>Back</IonButton>
                <IonButton color="success" onClick={toggleDisplayType}>{switchStr}</IonButton>
            </IonCol>
        </IonRow>
        {
            displayType === 'Sentiment'? <SentimentDisplay sentimentSorted={curatedTweets.sentimentSorted} /> :
            <TopicDisplay groupedByNP={curatedTweets.groupedByNp} />
         }
    </IonGrid>
);

Make sure to change the default export, and now we’re ready to implement the Topic Display Page.

Topic Display Page

Big-picture Plan

The topic display page is a list display similar to the sentiment display, but we will be looking for the topic in question from the route parameter.

Route Setup

If you’ve gotten this far, you should already know what to do. Let’s create a page folder called topicdisplay and a TopicDisplay.tsx, write a stub component, and import it into the App.tsx page. Now, let’s set up the routes:

<Route path="/topicDisplay/:topic" render={() => <TopicDisplay curatedTweets={curatedTweets} /> } />

Now we’re ready to implement the UI component.

UI Components

First, let’s create the ContainerProps definition:

interface ContainerProps {
    curatedTweets: CuratedTweets
}

const TopicDisplay: React.FC<ContainerProps> = ({curatedTweets}) => {
    Return <div>Topic Display</div>
}

Now, we will need to retrieve the topic from the URL path name. To do that, we will be using the history API. So let’s import useHistory, instantiate the history API, and pull the topic from the pathname. While we’re at it, let’s also implement the switch back functionality:

const TopicDisplay: React.FC<ContainerProps> = ({curatedTweets}) => {
    const history = useHistory();
    const switchToDisplay = () => {
        history.goBack();
    }
    const topic = history.location.pathname.split('/')[2];
    const tweets = (curatedTweets.groupedByNp || {})[topic];

Now that we have the tweets with that particular topic, displaying is actually quite simple:

return (
    <IonGrid>
        <IonRow>
            <IonCol>
                <IonButton color='primary' onClick={switchToDisplay}>Back</IonButton>
            </IonCol>
        </IonRow>
        <IonRow>
            <IonCol>
                <IonList>
                    {(tweets || []).map((x, i) => <IonItem key={i}>
                        <IonLabel className="ion-text-wrap">
                            <h2>{x.account}:</h2>
                            <h3>{x.tweet}</h3>
                            <p>({x.data.sentiment.toPrecision(2)})</p>
                        </IonLabel>
                    </IonItem>)}
                </IonList>
            </IonCol>
        </IonRow>
    </IonGrid>
);

Save and run, and things should be looking good.

Running the App in the Emulator

To run the app in the emulator, we simply run a few Ionic commands to add the mobile platform and copy the code over, similar to how we set things up with Cordova.

ionic build # builds the app
ionic cap add ios # adds iOS as one of the platforms, only have to run once
ionic cap copy # copy the build over
ionic cap sync # only need to run this if you added native plugins
ionic cap open ios # run the iOS emulator

And you should see the app show up.

React Native Implementation

React Native Primer

React Native takes a very different approach from the web-based approaches of the previous sections. React Native renders your React code as native components. This comes with several advantages. First, the integration with the underlying operating system is much deeper, which allows the developer to take advantage of new smartphone features and OS-specific features that may not be available through Cordova/Capacitor. Second, because there is no web-based rendering engine in the middle, a React Native app is generally faster than one written using Cordova. Finally, because React Native allows integration of native components, developers can exert much finer-grained control over their application.

For our application, we will use the logic from the previous sections and use a React Native component library called NativeBase to code up our UI.

Configuring the App

First, you will want to install all the requisite components of React Native following the instructions here.

Once React Native is installed, let’s start the project:

react-native init TwitterCurationRN

Let the setup script run, and eventually, the folder should be created. Cd into the folder and run react-native run-ios, and you should see the emulator pop up with the example app.

We will want to also install NativeBase since that is our component library. To do that, we run:

npm install --save native-base
react-native link

We also want to install the React Native stack navigator. Let’s run:

npm install --save @react-navigation/stack @react-navigation/native

And

react-native link
cd ios
pod-install
cd

To complete the linking and installation of the native plugins.

Router Setup

For routing, we will use the stack navigator that we installed in the above step.

Import the router components:

import { NavigationContainer } from '@react-navigation/native';
import {createStackNavigator} from '@react-navigation/stack';

And now, we create a stack navigator:

const Stack = createStackNavigator();

Change the content of the App component to use the stack navigator:

const App = () => {
  return (
    <>
      <StatusBar barStyle="dark-content" />
        <NavigationContainer>
          <Stack.Navigator initialRouteName="Entry">
            <Stack.Screen name="Entry" component={Entry} />
          </Stack.Navigator>
        </NavigationContainer>
    </>
  );
};

At this point, you will get an error because Entry is not yet defined. Let’s define a stub element just to make it happy.

Create a components folder in your project, create a file named Entry.jsx, and add a stub component like so:

import React, {useState} from 'react';
import { Text } from 'native-base';

export default Entry = ({navigation}) => {
    return <Text>Entry</Text>; // All text must be wrapped in a <Text /> component or <TextView /> if you’re not using NativeBase.
}

Import the Entry component in your app, and it should build.

Now, we’re ready to code the Input page.

Input Page

Big-picture Plan

We will be implementing a page that is very similar to the one implemented above but using NativeBase components. Most of the JavaScript and React APIs we used, such as hooks and fetch, are all still available.

The one difference will be the way we work with the navigation API, which you will see later.

UI Components

The additional NativeBase components we will use are Container, Content, Input, List, ListItem, and Button. These all have analogs in Ionic and Bootstrap React, and the builders of NativeBase have made it very intuitive for people familiar with these libraries. Simply import like so:

import { Container, Content, Input,

    Item, Button, List, ListItem, Text } from 'native-base';

And the component is:

return <Container>
        <Content>
          <Item regular>
            <Input placeholder='Input Handles Here' onChangeText={inputChange}
          value={input} />
            <Button primary onPress={onAddClicked}><Text> Add </Text></Button>
            <Text> </Text>
            <Button success onPress={onPullClicked}><Text> Pull </Text></Button>
          </Item>
        <Item>
                <List style={{width: '100%'}}>
                   {handles.map((item) => <ListItem key={item.key}>
                        <Text>{item.key}</Text>
                    </ListItem>)}
                </List>
          </Item>
        </Content>
      </Container>

And now, let’s implement the state and event handlers:

const [input, changeInput] = useState('');
    const [handles, changeHandles] = useState([]);
    const inputChange = (text) => {
        changeInput(text);
    }

   const onAddClicked = () => {
        const newHandles = [...handles, {key: input}];
        changeHandles(newHandles);
        changeInput('');
    }

And finally, the API call:

const onPullClicked = () => {
    fetch('http://prismatic.pythonanywhere.com/get_tweets', {
        method: 'POST',
        mode: 'cors',
        headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
        },
        body: JSON.stringify({
            accounts: handles.map(x => x.key)
        })
    }).then(r=>r.json()).then(data => {
        navigation.navigate('SentimentDisplay', { data });
    })
    .catch(e => {
        console.log(e);
    })
}

Notice that this implementation is the same as in the NativeBase implementation, except we are navigating in a different way. The stack navigator passes into its components a prop called “navigation,” and that can be used to navigate between routes with .navigate. In addition to simply navigating, you can also pass data to the target component. We will use this mechanism to pass the data.

To make the app compile, we still need to make Entry aware of the navigation component. To do that, we will need to change the component function declaration:

export default Entry = ({navigation}) => {

Now save, and you should see the page.

Sentiment Sorted Page

Big-picture Plan

We will be implementing the sentiment page much like the previous sections, but we will be styling the page a little differently, and we will also be using the navigation library differently to get the API call return value.

Because React Native doesn’t have CSS, we will either need to define a StyleSheet object or simply code the styles in-line. Because we will share some of the styling across components, let’s create a global stylesheet. We will do that after the route setup.

Also, because StackNavigator has an in-built Back navigation button, we won’t need to implement our own Back button.

Route Setup

Route definition in StackNavigator is very simple. We simply create a new one named Stack Screen and give it the component, much like the React router.

 <NavigationContainer>
    <Stack.Navigator initialRouteName="Entry">
        <Stack.Screen name="Entry" component={Entry} />
        <Stack.Screen name="SentimentDisplay" component={SentimentDisplay} />
    </Stack.Navigator>
</NavigationContainer>

To make this work, we will of course need to create a stub component in components/SentimentDisplay.js:

import React from 'react';
import {Text} from 'native-base';

const SentimentDisplay = () => {
    return <Text>Sentiment Display</Text>;
}

export default SentimentDisplay;

And import it:

import SentimentDisplay from './components/SentimentDisplay';

Now, we’re ready to create the global stylesheet.

Global StyleSheet

First, create a file named globalStyles.js. Then, import the StyleSheet component from React Native and define the styles:

import {StyleSheet} from 'react-native';

export default StyleSheet.create({
    tweet: {paddingTop: 5},
    accountName: {fontWeight: '600'},
})

And we’re ready to code the UI.

UI Components

The UI component is pretty familiar, with the exception of how we work with the routes. We will want to use StackNavigator’s special props navigation and route to get the current application state and to navigate to the topic display should the user want to see that page.

Change the component definition to access the navigation props:

const SentimentDisplay = ({route, navigation}) => {

And now, we implement the application state read and the navigation functionality:

const {params: {data}} = route;
const viewByTopicClicked = () => {
    navigation.navigate('TopicDisplay', { data });
}

Import the global styles:

import globalStyles from './globalStyles';

And the components:

import { View } from 'react-native';
import {List, Item, Content, ListItem, Container, Text, Button} from 'native-base'; 

And finally, the components:

return <Container>
    <Content>
        <Item>
         <Button primary onPress={viewByTopicClicked}><Text>View By Topic</Text></Button>
        </Item>
        <Item>
            <List style={{width: '100%'}}>
                {data.sentimentSorted.map((item, i) => <ListItem key={i}>
                    <View style={globalStyles.listItem}>
                    <Text style={globalStyles.accountName}>{item.account}:</Text>
                    <Text style={globalStyles.tweet}>{item.tweet} ({item.data.sentiment.toPrecision(2)})</Text>
                    </View>
                </ListItem>)}
            </List>
        </Item>
    </Content>
</Container>;

Save and try to pull some tweets, and you should see the sentiment display. Now onto the topic grouping page.

Topic Grouping Page

Big-picture Plan

Topic Display is again very similar. We will be using a handler builder to build a navigation function to navigate to the display page for a specific topic item, and we will also be defining a stylesheet that is specific to this page.

One new thing we will be doing is implementing a TouchableOpacity, which is a React Native specific component that functions much like a button.

Route Setup

Route definition is the same as before:

<Stack.Navigator initialRouteName="Entry">
    <Stack.Screen name="Entry" component={Entry} />
    <Stack.Screen name="SentimentDisplay" component={SentimentDisplay} />
    <Stack.Screen name="TopicDisplay" component={TopicDisplay} />
</Stack.Navigator>

The stub component components/TopicDisplay.js:

import React from 'react';
import {Text} from 'native-base';

const TopicDisplay = () => {
    return <Text>Topic Display</Text>;
} 

export default TopicDisplay;

And import it:

import TopicDisplay from './components/TopicDisplay;

UI Components

A lot of this will look very familiar. Import the library functions:

import {
   View,
   TouchableOpacity,
   StyleSheet
 } from 'react-native';
import {List, Item, Content, ListItem, Container, Text} from 'native-base';

Import the global styles:

import globalStyles from './globalStyles';

Define the custom styles:

const styles = StyleSheet.create({
    topicName: {fontWeight: '600'},
})

Define the navigation props:

export default TopicDisplay = ({route, navigation}) => {

Define the data and action handlers. Notice we’re using a handler builder, a function that returns a function:

const {params: {data}} = route;
const specificItemPressedHandlerBuilder = (topic) => () => {
    navigation.navigate('TopicDisplayItem', { data, topic });
}

And now, the components. Notice that we’re using a TouchableOpacity, which can have an onPress handler. We could have used TouchableTransparency as well, but TouchableOpacity’s click-and-hold animation was better suited for our application.

return <Container>
    <Content>
        <Item>
            <List style={{width: '100%'}}>
                {Object.keys(data.groupedByNp).map((topic, i) => <ListItem key={i}>
                    <View style={globalStyles.listItem}>
                    <TouchableOpacity onPress={specificItemPressedHandlerBuilder(topic)}>
                        <Text style={styles.topicName}>{topic}</Text>
                    </TouchableOpacity>
                    </View>
                </ListItem>)}
            </List>
        </Item>
    </Content>
 </Container>;

And this should do it. Save and try out the application!

Now, onto the Topic Display Item Page.

Topic Display Item Page

Big-picture Plan

The Topic Display Item page is very similar and all the idiosyncrasies are taken care of in the other sections so it should be smooth sailing from here.

Route Setup

We’ll add the route definition:

<Stack.Screen name="TopicDisplayItem" component={TopicDisplayItem} />

Add the import:

import TopicDisplayItem from './components/TopicDisplayItem';

And create the stub component. Instead of just a bare component, let’s also import the NativeBase components we’ll be using and define the route props:

import React from 'react';
import {View} from 'react-native';
import {List, Item, Content, ListItem, Container, Text} from 'native-base';
 
import globalStyles from './globalStyles';
 
const TopicDisplayItem = ({route}) => {
    const {params: {data, topic}} = route;
    return <Text>Topic Display Item</Text>;
}
 
export default TopicDisplayItem;

UI Components

The UI Component is quite simple. We have seen it before and we’re not really implementing any custom logic. So, let’s just go for it! Take a deep breath…

return <Container>
    <Content>
        <Item>
            <List style={{width: '100%'}}>
                {data.groupedByNp[topic].map((item, i) => <ListItem key={i}>
                    <View style={globalStyles.listItem}>
                    <Text style={globalStyles.accountName}>{item.account}:</Text>
                    <Text style={globalStyles.tweet}>{item.tweet} ({item.data.sentiment.toPrecision(2)})</Text>
                    </View>
                </ListItem>)}
            </List>
        </Item>
    </Content>
</Container>;

Save, and we should be good to go! Now we’re ready to run the app in the emulator… wait, haven’t we already?

Running the App

Well, since you’re working with React Native, you’re already running the app in the emulator so this part is already taken care of. This is one of the great things about React Native’s development environment.

Whew! With that, we’re done with the coding portion of this article. Let’s see what we learned about the technologies.

Comparing the Technologies

Cordova: Pros and Cons

The best thing about Cordova is the sheer speed with which a skilled web developer can code up something functional and reasonably presentable. Web development skills and experience transfer over easily because, after all, you are coding a web app. The development process is quick and simple, and accessing Cordova API is simple and intuitive as well.

The drawbacks of using Cordova directly comes mostly from the over-reliance on web components. Users have come to expect a specific user experience and interface design when using mobile apps, and when an application feels like a mobile site, the experience can be a bit jarring. Additionally, most of the features built into apps, such as transitional animations and navigation utilities, must be implemented manually.

Ionic: Pros and Cons

The best part of Ionic was how many mobile-centric features I got for “free.” By coding much like I would have coded a web application, I was able to build an app that looks a lot more mobile-friendly than simply using Cordova and React-Bootstrap. There was navigation animation, buttons with native-looking styles, and many user interface options that made the user experience very smooth.

The drawback of using Ionic was partially caused by its strengths. First, it was sometimes hard to envision how the app would behave in various environments. Just because the app looked one way did not mean that the same UI placement would look the same in another environment. Second, Ionic sits on top of many pieces of underlying technologies, and getting access to some of the components proved difficult. Lastly, this is specific to Ionic-React, but because Ionic was first built for Angular, many Ionic-React features seemed to have less documentation and support. However, the Ionic team seems very attentive to the needs of React developers and delivers new features quickly.

React Native: Pros and Cons

React Native had a very smooth user experience developing on mobile. By connecting directly to the emulator, it was no mystery how the application would look. The web-based debugger interface was extremely helpful in cross-applying debugging techniques from the web application world, and the ecosystem is quite robust.

The drawback of React Native comes from its proximity to the native interface. Many DOM-based libraries could not be used, which meant having to learn new libraries and best practices. Without the benefit of CSS, styling the application was somewhat less intuitive. Finally, with many new components to learn (e.g., View instead of div, Text component wrapping everything, Buttons vs. TouchableOpacity vs. TouchableTransparency, etc.), there is a bit of a learning curve in the beginning if someone is coming into the React Native world with little prior knowledge of the mechanics.

When to Use Each Technology

Because Cordova, Ionic, and React Native all have very strong pros and cons, each technology has a context in which it would enjoy the best productivity and performance.

If you already have an existing application that is web-first with a strong brand identity surrounding the UI design and general look and feel, your best option would be Cordova, which gives you access to the smartphone’s native features while letting you reuse most of your web components and preserve your brand identity in the process. For relatively simple applications using a responsive framework, you may be able to build a mobile app with very few changes required. However, your application will look less like an app and more like a web page, and some of the components people expect from a mobile app will be coded separately. Therefore, I recommend Cordova in cases where you’re in a web-first project porting the application over to mobile.

If you are starting to code a new application with an app-first philosophy, but your team’s skill set is primarily in web development, I recommend Ionic. Ionic’s library lets you quickly write code that looks and feels close to native components while letting you apply your skills and instincts as a web developer. I found that web development best practices readily cross-applied to developing with Ionic, and styling with CSS worked seamlessly. In addition, the mobile version of the site looks much more native than a website coded using a responsive CSS framework. However, at some steps along the way, I found that the React-Ionic-Native API integration requires some manual adjustment, which could prove time-consuming. Therefore, I recommend Ionic in cases where your application is being developed from the ground up and you want to share a significant amount of code between a mobile-capable web application and a mobile application.

If you are coding a new application with some native codebase implemented, you may want to try React Native. Even if you’re not using native code, it could also be the best option in cases where you’re already familiar with React Native, or when your primary concern is the mobile application rather than a hybrid application. Having focused most of my front-end development efforts on web development, I initially found that getting started with React Native had more of a learning curve than Ionic or Cordova due to the differences in component organization and coding conventions. However, once these nuances are learned, the coding experience is quite smooth, especially with the help of a component library like NativeBase. Given the quality of the development environment and control over the application, if your project’s front end is primarily a mobile application, I would recommend React Native as your tool of choice.

Future Topics

One of the topics that I did not have time to explore was the ease of accessing native APIs such as camera, geolocation, or biometric authentication. One of the great benefits of mobile development is the accessibility of a rich API ecosystem that is generally not accessible on the browser.

In future articles, I would like to explore the ease of developing these native API-enabled applications using various cross-platform technologies.

Conclusion

Today, we implemented a Twitter curation app using three different cross-platform mobile development technologies. I hope this gave you a good sense of what each technology is like and inspired you to develop your own React-based application.

You can find the code associated with the tutorial on GitHub.

Original article source at: https://www.toptal.com/

#ionic #cordova #reactnative 

Ionic vs. Cordova vs. React Native
Saul  Alaniz

Saul Alaniz

1657091700

Cómo Agregar Teclado En La Aplicación Ionic 6

El teclado ayuda a los usuarios a escribir lo que quieran; en aplicaciones iónicas, agregar un teclado es simple. Ionic ofrece una gran cantidad de complementos para crear funciones similares a las aplicaciones móviles nativas fácilmente.

En este tutorial, compartiremos cómo administrar el teclado en aplicaciones iónicas. Comprenderá cómo instalar y configurar los complementos de teclado nativo de Cordova e Ionic en las aplicaciones de Ionic.

Esta guía lo familiarizará con los eventos de los complementos de teclado que son significativamente importantes. Y te dice cómo integrar la funcionalidad del teclado en ionic.

Cómo agregar teclado en la aplicación Ionic 6

  • Paso 1: configurar la aplicación Ionic
  • Paso 2: Instale paquetes de teclado iónico
  • Paso 3: registre el complemento de teclado en el módulo de la aplicación
  • Paso 4: administrar el teclado en TypeScript

Configurar la aplicación iónica

Para comenzar, debe tener una aplicación Ionic instalada en su sistema.

Sin embargo, si aún no lo ha descargado, ejecute el comando sugerido para crear la nueva aplicación iónica.

ionic start IonicCosmos blank --type=angular

Vaya dentro de la carpeta del proyecto.

cd IonicCosmos

Instalar paquetes de teclado iónico

Estos son los comandos que debe invocar desde la ventana del terminal.

Estos comandos instalarán los paquetes de teclado iónico necesarios en la aplicación Ionic.

ionic cordova plugin add cordova-plugin-ionic-keyboard
npm install @ionic-native/keyboard

Registro del complemento de teclado en el módulo de la aplicación

En el siguiente paso, importará el módulo Teclado en la clase del módulo de la aplicación.

Por lo tanto, diríjase al archivo app.module.ts y agregue el código dado dentro del archivo.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
// Register module
import { Keyboard } from '@ionic-native/keyboard/ngx';
@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
  providers: [
    {
      provide: RouteReuseStrategy,
      useClass: IonicRouteStrategy,
    },
    Keyboard
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

Primero, importe el módulo de teclado del paquete '@ionic-native/keyboard/ngx'; en segundo lugar, agregue el módulo de teclado en la matriz de proveedores.

Teclado incrustado en Ionic

Para manejar el teclado, debe definir el código dado en el archivo home.page.ts.

import { Component } from '@angular/core';
import { Keyboard } from '@ionic-native/keyboard/ngx';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})

export class HomePage {
  constructor(private keyboard: Keyboard) {
    window.addEventListener('keyboardDidShow', () => {
      
    });
    window.addEventListener('keyboardWillShow', () => {
      
    });    
    window.addEventListener('keyboardWillHide', () => {
      
    });
    window.addEventListener('keyboardDidHide', () => {
      
    });
  }
  showIonKeyboard() {
    this.keyboard.show();
  }
  hideIonKeyboard() {
    this.keyboard.hide();
  }
}

Para administrar el teclado en Ionic, puede usar los siguientes eventos.

Este evento se activa cuando el teclado está completamente abierto.

window.addEventListener('keyboardDidShow', () => {
  
});

Este evento se llama antes de que se muestre el teclado.

window.addEventListener('keyboardWillShow', () => {
      
});

Este evento se evoca antes de que se cierre el teclado.

window.addEventListener('keyboardWillHide', () => {
      
});

Este evento se dispara cuando el teclado está completamente cerrado.

window.addEventListener('keyboardDidHide', () => {
      
});

Conclusión

Aquí, en esta guía rápida, finalmente encontramos una forma sencilla de controlar el comportamiento del teclado. Hemos revelado cómo lidiar con las funciones del teclado en la plataforma iónica.

Fuente: https://www.positronx.io/ionic-keyboard-with-cordova-and-ionic-native-tutorial/

#cordova #ionic

Cómo Agregar Teclado En La Aplicación Ionic 6
Trung  Nguyen

Trung Nguyen

1657091580

Cách Thêm Bàn Phím Trong Ứng Dụng Ionic 6

Bàn phím giúp người dùng gõ bất cứ thứ gì họ muốn; trong các ứng dụng ion, việc thêm bàn phím rất đơn giản. Ionic cung cấp rất nhiều plugin để tạo ra các tính năng tương tự như các ứng dụng di động gốc một cách dễ dàng.

Trong hướng dẫn này, chúng tôi sẽ chia sẻ cách quản lý bàn phím trong các ứng dụng ion. Bạn sẽ hiểu cách cài đặt và cấu hình các plugin bàn phím gốc Cordova và Ionic trong các ứng dụng Ionic.

Hướng dẫn này sẽ giúp bạn làm quen với các sự kiện của plugin bàn phím có vai trò quan trọng đáng kể. Và cho bạn biết cách tích hợp chức năng bàn phím trong ionic.

Cách thêm bàn phím trong ứng dụng Ionic 6

  • Bước 1: Thiết lập ứng dụng Ionic
  • Bước 2: Cài đặt Gói bàn phím Ionic
  • Bước 3: Đăng ký Plugin bàn phím trong Mô-đun ứng dụng
  • Bước 4: Quản lý bàn phím trong TypeScript

Thiết lập ứng dụng Ionic

Để bắt đầu, bạn phải cài đặt ứng dụng Ionic trên hệ thống của mình.

Tuy nhiên, nếu bạn chưa tải xuống, hãy thực hiện lệnh được đề xuất để tạo ứng dụng ion mới.

ionic start IonicCosmos blank --type=angular

Vào bên trong thư mục dự án.

cd IonicCosmos

Cài đặt Gói bàn phím Ionic

Dưới đây là các lệnh mà bạn cần gọi từ cửa sổ đầu cuối.

Các lệnh này sẽ cài đặt các gói bàn phím ion được yêu cầu trong ứng dụng Ionic.

ionic cordova plugin add cordova-plugin-ionic-keyboard
npm install @ionic-native/keyboard

Đăng ký Plugin bàn phím trong Mô-đun ứng dụng

Trong bước tiếp theo, bạn sẽ nhập mô-đun Bàn phím trong lớp mô-đun ứng dụng.

Do đó, hãy truy cập tệp app.module.ts và thêm mã đã cho vào tệp.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
// Register module
import { Keyboard } from '@ionic-native/keyboard/ngx';
@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
  providers: [
    {
      provide: RouteReuseStrategy,
      useClass: IonicRouteStrategy,
    },
    Keyboard
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

Đầu tiên, nhập mô-đun Bàn phím từ gói '@ ionic-native / keyboard / ngx'; thứ hai thêm mô-đun Bàn phím trong mảng của nhà cung cấp.

Bàn phím nhúng trong Ionic

Để xử lý bàn phím, bạn phải xác định mã đã cho trong tệp home.page.ts.

import { Component } from '@angular/core';
import { Keyboard } from '@ionic-native/keyboard/ngx';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})

export class HomePage {
  constructor(private keyboard: Keyboard) {
    window.addEventListener('keyboardDidShow', () => {
      
    });
    window.addEventListener('keyboardWillShow', () => {
      
    });    
    window.addEventListener('keyboardWillHide', () => {
      
    });
    window.addEventListener('keyboardDidHide', () => {
      
    });
  }
  showIonKeyboard() {
    this.keyboard.show();
  }
  hideIonKeyboard() {
    this.keyboard.hide();
  }
}

Để quản lý bàn phím trong Ionic, bạn có thể sử dụng các sự kiện sau.

Sự kiện này được kích hoạt khi bàn phím mở hoàn toàn.

window.addEventListener('keyboardDidShow', () => {
  
});

Sự kiện này được gọi trước khi bàn phím được hiển thị.

window.addEventListener('keyboardWillShow', () => {
      
});

Sự kiện này được gợi lên trước khi bàn phím được đóng lại.

window.addEventListener('keyboardWillHide', () => {
      
});

Sự kiện này được kích hoạt khi bàn phím đóng hoàn toàn.

window.addEventListener('keyboardDidHide', () => {
      
});

Sự kết luận

Ở đây trong hướng dẫn nhanh này, cuối cùng chúng tôi đã tìm thấy một cách đơn giản để kiểm soát hoạt động của bàn phím. Chúng tôi đã tiết lộ cách xử lý các tính năng bàn phím trong nền tảng ion.

Nguồn: https://www.positronx.io/ionic-keyboard-with-cordova-and-ionic-native-tutorial/

#cordova #ionic 

Cách Thêm Bàn Phím Trong Ứng Dụng Ionic 6
Anne  de Morel

Anne de Morel

1657087920

Comment Ajouter Un Clavier Dans L'application Ionic 6

Le clavier aide les utilisateurs à taper ce qu'ils veulent ; dans les applications ioniques, l'ajout d'un clavier est simple. Ionic propose une pléthore de plugins pour créer facilement des fonctionnalités similaires aux applications mobiles natives.

Dans ce tutoriel, nous partagerons comment gérer le clavier dans les applications ioniques. Vous comprendrez comment installer et configurer les plug-ins de clavier natifs Cordova et Ionic dans les applications Ionic.

Ce guide vous familiarisera avec les événements des plugins de clavier qui sont très importants. Et vous explique comment intégrer la fonctionnalité du clavier dans ionic.

Comment ajouter un clavier dans l'application Ionic 6

  • Étape 1 : Configurer l'application Ionic
  • Étape 2 : Installer les packages de clavier Ionic
  • Étape 3 : Enregistrez le plugin de clavier dans le module d'application
  • Étape 4 : Gérer le clavier dans TypeScript

Configurer l'application Ionic

Pour commencer, vous devez avoir une application Ionic installée sur votre système.

Cependant, si vous ne l'avez pas encore téléchargé, exécutez la commande suggérée pour créer la nouvelle application ionique.

ionic start IonicCosmos blank --type=angular

Allez dans le dossier du projet.

cd IonicCosmos

Installer les packages de clavier ionique

Voici les commandes que vous devez appeler depuis la fenêtre du terminal.

Ces commandes installeront les packages de clavier ionique requis dans l'application Ionic.

ionic cordova plugin add cordova-plugin-ionic-keyboard
npm install @ionic-native/keyboard

Enregistrez le plug-in de clavier dans le module d'application

Dans l'étape suivante, vous importerez le module Keyboard dans la classe du module app.

Par conséquent, dirigez-vous vers le fichier app.module.ts et ajoutez le code donné dans le fichier.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
// Register module
import { Keyboard } from '@ionic-native/keyboard/ngx';
@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
  providers: [
    {
      provide: RouteReuseStrategy,
      useClass: IonicRouteStrategy,
    },
    Keyboard
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

Tout d'abord, importez le module Keyboard du package '@ionic-native/keyboard/ngx' ; ajoutez ensuite le module Keyboard dans le tableau des fournisseurs.

Intégrer le clavier dans Ionic

Afin de gérer le clavier, vous devez définir le code donné dans le fichier home.page.ts.

import { Component } from '@angular/core';
import { Keyboard } from '@ionic-native/keyboard/ngx';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})

export class HomePage {
  constructor(private keyboard: Keyboard) {
    window.addEventListener('keyboardDidShow', () => {
      
    });
    window.addEventListener('keyboardWillShow', () => {
      
    });    
    window.addEventListener('keyboardWillHide', () => {
      
    });
    window.addEventListener('keyboardDidHide', () => {
      
    });
  }
  showIonKeyboard() {
    this.keyboard.show();
  }
  hideIonKeyboard() {
    this.keyboard.hide();
  }
}

Pour gérer le clavier dans Ionic, vous pouvez utiliser les événements suivants.

Cet événement est déclenché lorsque le clavier est complètement ouvert.

window.addEventListener('keyboardDidShow', () => {
  
});

Cet événement est appelé avant que le clavier ne soit affiché.

window.addEventListener('keyboardWillShow', () => {
      
});

Cet événement est évoqué avant la fermeture du clavier.

window.addEventListener('keyboardWillHide', () => {
      
});

Cet événement est déclenché lorsque le clavier est complètement fermé.

window.addEventListener('keyboardDidHide', () => {
      
});

Conclusion

Ici, dans ce guide rapide, nous avons finalement trouvé un moyen simple de contrôler le comportement du clavier. Nous avons révélé comment gérer les fonctionnalités du clavier dans la plate-forme ionique.

Source : https://www.positronx.io/ionic-keyboard-with-cordova-and-ionic-native-tutorial/

#cordova #ionic 

Comment Ajouter Un Clavier Dans L'application Ionic 6
曾 俊

曾 俊

1657087500

如何在 Ionic 6 应用程序中添加键盘

键盘可以帮助用户输入他们想要的任何内容;在 ionic 应用程序中,添加键盘很简单。Ionic 提供了大量插件来轻松创建类似于原生移动应用程序的功能。

在本教程中,我们将分享如何在 ionic 应用程序中管理键盘。您将了解如何在 Ionic 应用程序中安装和配置 Cordova 和 Ionic 本机键盘插件。

本指南将使您熟悉非常重要的键盘插件事件。并告诉你如何在ionic中集成键盘功能。

如何在 Ionic 6 应用程序中添加键盘

  • 第 1 步:设置 Ionic 应用程序
  • 第 2 步:安装离子键盘包
  • 第 3 步:在 App 模块中注册键盘插件
  • 第 4 步:在 TypeScript 中管理键盘

设置离子应用程序

为了开始,您必须在系统上安装 Ionic 应用程序。

但是,如果您还没有下载它,请执行建议的命令来创建新的 ionic 应用程序。

ionic start IonicCosmos blank --type=angular

进入项目文件夹。

cd IonicCosmos

安装离子键盘包

以下是您需要从终端窗口调用的命令。

这些命令将在 Ionic 应用程序中安装所需的离子键盘包。

ionic cordova plugin add cordova-plugin-ionic-keyboard
npm install @ionic-native/keyboard

在 App 模块中注册键盘插件

在下一步中,您将在应用模块类中导入键盘模块。

因此,转到app.module.ts文件,并在文件中添加给定的代码。

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
// Register module
import { Keyboard } from '@ionic-native/keyboard/ngx';
@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
  providers: [
    {
      provide: RouteReuseStrategy,
      useClass: IonicRouteStrategy,
    },
    Keyboard
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

首先,从 '@ionic-native/keyboard/ngx' 包中导入键盘模块;其次在提供者的数组中添加键盘模块。

在 Ionic 中嵌入键盘

为了处理键盘,您已经在home.page.ts文件中定义了给定的代码。

import { Component } from '@angular/core';
import { Keyboard } from '@ionic-native/keyboard/ngx';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})

export class HomePage {
  constructor(private keyboard: Keyboard) {
    window.addEventListener('keyboardDidShow', () => {
      
    });
    window.addEventListener('keyboardWillShow', () => {
      
    });    
    window.addEventListener('keyboardWillHide', () => {
      
    });
    window.addEventListener('keyboardDidHide', () => {
      
    });
  }
  showIonKeyboard() {
    this.keyboard.show();
  }
  hideIonKeyboard() {
    this.keyboard.hide();
  }
}

要在 Ionic 中管理键盘,您可以使用以下事件。

当键盘完全打开时触发此事件。

window.addEventListener('keyboardDidShow', () => {
  
});

在显示键盘之前调用此事件。

window.addEventListener('keyboardWillShow', () => {
      
});

此事件在键盘关闭之前触发。

window.addEventListener('keyboardWillHide', () => {
      
});

当键盘完全关闭时触发此事件。

window.addEventListener('keyboardDidHide', () => {
      
});

结论

在本快速指南中,我们最终找到了一种控制键盘行为的简单方法。我们已经揭示了如何处理 ionic 平台中的键盘功能。

来源:https ://www.positronx.io/ionic-keyboard-with-cordova-and-ionic-native-tutorial/

#cordova #ionic 

如何在 Ionic 6 应用程序中添加键盘
Mélanie  Faria

Mélanie Faria

1657083900

Como Adicionar Teclado No Aplicativo Ionic 6

O teclado ajuda os usuários a digitar o que quiserem; em aplicativos iônicos, adicionar um teclado é simples. O Ionic oferece uma infinidade de plugins para criar recursos semelhantes aos aplicativos móveis nativos facilmente.

Neste tutorial, compartilharemos como gerenciar o teclado em aplicativos iônicos. Você entenderá como instalar e configurar plugins de teclado nativos Cordova e Ionic em aplicativos Ionic.

Este guia o familiarizará com os eventos de plug-ins de teclado que são significativamente importantes. E informa como integrar a funcionalidade do teclado no ionic.

Como adicionar teclado no aplicativo Ionic 6

  • Etapa 1: configurar o aplicativo Ionic
  • Etapa 2: instalar pacotes de teclado Ionic
  • Etapa 3: registrar o plug-in do teclado no módulo do aplicativo
  • Etapa 4: gerenciar o teclado no TypeScript

Configurar aplicativo Ionic

Para começar, você deve ter um aplicativo Ionic instalado em seu sistema.

No entanto, se você ainda não o baixou, execute o comando sugerido para criar o novo aplicativo iônico.

ionic start IonicCosmos blank --type=angular

Entre na pasta do projeto.

cd IonicCosmos

Instalar pacotes de teclado Ionic

Aqui estão os comandos que você precisa invocar na janela do terminal.

Esses comandos instalarão os pacotes de teclado iônico necessários no aplicativo Ionic.

ionic cordova plugin add cordova-plugin-ionic-keyboard
npm install @ionic-native/keyboard

Registrar o plug-in do teclado no módulo do aplicativo

Na próxima etapa, você estará importando o módulo Keyboard na classe do módulo app.

Portanto, vá para o arquivo app.module.ts e adicione o código fornecido dentro do arquivo.

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
// Register module
import { Keyboard } from '@ionic-native/keyboard/ngx';
@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
  providers: [
    {
      provide: RouteReuseStrategy,
      useClass: IonicRouteStrategy,
    },
    Keyboard
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

Primeiro, importe o módulo Keyboard do pacote '@ionic-native/keyboard/ngx'; em segundo lugar, adicione o módulo Keyboard na matriz dos provedores.

Incorporar teclado em Ionic

Para lidar com o teclado, você definiu o código fornecido no arquivo home.page.ts.

import { Component } from '@angular/core';
import { Keyboard } from '@ionic-native/keyboard/ngx';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})

export class HomePage {
  constructor(private keyboard: Keyboard) {
    window.addEventListener('keyboardDidShow', () => {
      
    });
    window.addEventListener('keyboardWillShow', () => {
      
    });    
    window.addEventListener('keyboardWillHide', () => {
      
    });
    window.addEventListener('keyboardDidHide', () => {
      
    });
  }
  showIonKeyboard() {
    this.keyboard.show();
  }
  hideIonKeyboard() {
    this.keyboard.hide();
  }
}

Para gerenciar o teclado no Ionic, você pode usar os seguintes eventos.

Este evento é acionado quando o teclado está totalmente aberto.

window.addEventListener('keyboardDidShow', () => {
  
});

Este evento é chamado antes que o teclado seja mostrado.

window.addEventListener('keyboardWillShow', () => {
      
});

Este evento é evocado antes que o teclado seja fechado.

window.addEventListener('keyboardWillHide', () => {
      
});

Este evento é acionado quando o teclado está totalmente fechado.

window.addEventListener('keyboardDidHide', () => {
      
});

Conclusão

Aqui neste guia rápido, finalmente encontramos uma maneira simples de controlar o comportamento do teclado. Revelamos como lidar com os recursos do teclado na plataforma iônica.

Fonte: https://www.positronx.io/ionic-keyboard-with-cordova-and-ionic-native-tutorial/

#cordova #ionic 

Como Adicionar Teclado No Aplicativo Ionic 6

Ionic6アプリケーションにキーボードを追加する

キーボードは、ユーザーが好きなように入力するのに役立ちます。イオンアプリでは、キーボードの追加は簡単です。Ionicは、ネイティブモバイルアプリと同様の機能を簡単に作成するための多数のプラグインを提供しています。

このチュートリアルでは、イオンアプリでキーボードを管理する方法を共有します。IonicアプリにCordovaおよびIonicネイティブキーボードプラグインをインストールして構成する方法を理解します。

このガイドでは、非常に重要なキーボードプラグインのイベントについて理解します。また、キーボード機能をionicに統合する方法についても説明します。

Ionic6アプリケーションにキーボードを追加する方法

  • ステップ1: Ionicアプリを設定する
  • ステップ2: Ionicキーボードパッケージをインストールする
  • ステップ3:キーボードプラグインをAppModuleに登録する
  • ステップ4: TypeScriptでキーボードを管理する

Ionicアプリを設定する

開始するには、システムにIonicアプリケーションがインストールされている必要があります。

ただし、まだダウンロードしていない場合は、提案されたコマンドを実行して新しいイオンアプリを作成してください。

ionic start IonicCosmos blank --type=angular

プロジェクトフォルダ内に移動します。

cd IonicCosmos

Ionicキーボードパッケージをインストールする

ターミナルウィンドウから呼び出す必要のあるコマンドは次のとおりです。

これらのコマンドは、必要なイオンキーボードパッケージをIonicアプリにインストールします。

ionic cordova plugin add cordova-plugin-ionic-keyboard
npm install @ionic-native/keyboard

AppModuleにキーボードプラグインを登録する

次のステップでは、appモジュールクラスにKeyboardモジュールをインポートします。

したがって、app.module.tsファイルに移動し、指定されたコードをファイル内に追加します。

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';
import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';
// Register module
import { Keyboard } from '@ionic-native/keyboard/ngx';
@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule],
  providers: [
    {
      provide: RouteReuseStrategy,
      useClass: IonicRouteStrategy,
    },
    Keyboard
  ],
  bootstrap: [AppComponent],
})
export class AppModule {}

まず、「@ ionic-native /keyboard/ngx」パッケージからキーボードモジュールをインポートします。次に、プロバイダーの配列にキーボードモジュールを追加します。

Ionicにキーボードを埋め込む

キーボードを処理するために、 home.page.tsファイルで指定されたコードを定義しました。

import { Component } from '@angular/core';
import { Keyboard } from '@ionic-native/keyboard/ngx';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})

export class HomePage {
  constructor(private keyboard: Keyboard) {
    window.addEventListener('keyboardDidShow', () => {
      
    });
    window.addEventListener('keyboardWillShow', () => {
      
    });    
    window.addEventListener('keyboardWillHide', () => {
      
    });
    window.addEventListener('keyboardDidHide', () => {
      
    });
  }
  showIonKeyboard() {
    this.keyboard.show();
  }
  hideIonKeyboard() {
    this.keyboard.hide();
  }
}

Ionicでキーボードを管理するには、次のイベントを使用できます。

このイベントは、キーボードが完全に開いているときにトリガーされます。

window.addEventListener('keyboardDidShow', () => {
  
});

このイベントは、キーボードが表示される前に呼び出されます。

window.addEventListener('keyboardWillShow', () => {
      
});

このイベントは、キーボードが閉じられる前に呼び出されます。

window.addEventListener('keyboardWillHide', () => {
      
});

このイベントは、キーボードが完全に閉じたときに発生します。

window.addEventListener('keyboardDidHide', () => {
      
});

結論

このクイックガイドでは、最終的にキーボードの動作を制御する簡単な方法を見つけました。イオンプラットフォームでキーボード機能を処理する方法を明らかにしました。

ソース:https ://www.positronx.io/ionic-keyboard-with-cordova-and-ionic-native-tutorial/

#cordova #ionic

Ionic6アプリケーションにキーボードを追加する

How to Add Keyboard in Ionic 6 Application

The keyboard helps users type whatever they want; in ionic apps, adding a keyboard is simple. Ionic offers a plethora of plugins to create features similar to native mobile apps easily.

In this tutorial, we will share how to manage the keyboard in ionic apps. You will understand how to install and configure Cordova and Ionic native keyboard plugins in Ionic apps.

This guide will make you familiar with the events of keyboard plugins that are significantly important. And tells you how to integrate the keyboard functionality in ionic.

See more at: https://www.positronx.io/ionic-keyboard-with-cordova-and-ionic-native-tutorial/

#cordova #ionic 

How to Add Keyboard in Ionic 6 Application

Sign in with Apple - Guide for App Owners

https://www.blog.duomly.com/sign-in-with-apple-guide/

Apple has announced a new sign-in feature called “Sign In with Apple.” This new feature will allow users to sign in to apps and websites using their Apple ID rather than creating a separate username and password. 

Here’s what you need to know about how Sign In with Apple will work for app owners.

#ios #mobile #mobile-apps #flutter #ionic #cordova #xamarin #nativescript #startup #startups 

Sign in with Apple - Guide for App Owners

How to Submit App to The App Store - Guide for Business Owners

https://www.blog.duomly.com/how-to-submit-app-to-app-store/

If you’re a business owner, you know that having an app can be a huge advantage. 

Not only does it make your business more accessible to customers, but it also allows you to communicate with them directly and keep them updated on the latest news and specials. But how do you get your app on the App Store? 

In this article, we’ll walk you through the process of submitting your app for approval.

#ios #mobile-apps #react-native #ionic #flutter #cordova #startup #startups #business 

How to Submit App to The App Store - Guide for Business Owners

21 Amazing React Native Apps Examples - 2022 Edition

https://www.blog.duomly.com/react-native-apps-examples/

In the past, if you wanted to create a mobile app, you had to learn a whole new language – Objective C or Swift if you were targeting iOS, Java if you were targeting Android. And even once you learned the language, you still faced the challenge of mastering all the intricacies of mobile app development.

But those days are gone. With React Native, you can use JavaScript (the same language that powers websites like Facebook and Netflix) to create apps that run on both iOS and Android devices.

In this article, we're going to take a look at some examples of apps that have been built with React Native.

#mobile-apps #react-native #react #flutter mobile development #ios #ionic #cordova #pwa 

21 Amazing React Native Apps Examples - 2022 Edition
Samanta  Moore

Samanta Moore

1638591600

How to Use The Cordova Plugin To Call Java APIs in JavaScript & Java

Cordova is an open-source cross-platform development framework that allows you to use HTML and JavaScript to develop apps across multiple platforms, such as Android and iOS. So how exactly does Cordova enable apps to run on different platforms and implement the functions?

Here, I'll use the Cordova plugin in HUAWEI Push Kit as an example to demonstrate how to call Java APIs in JavaScript through JavaScript-Java messaging. The following implementation principles can be applied to all other kits, except for Map Kit and Ads Kit (which will be detailed later), and help you master troubleshooting solutions.

  1. Basic Structure of Cordova
  2. Plugin Call

#java #javascript #cordova 

How to Use The Cordova Plugin To Call Java APIs in JavaScript & Java
Josefa  Corwin

Josefa Corwin

1632034800

Tutorial How to Make A Mobile Phone using cordova.

Hello guys in this video we will build a mobile with cordova.

#cordova 

Tutorial How to Make A Mobile Phone using cordova.
Josefa  Corwin

Josefa Corwin

1632013200

Tutorial How to install and Uninstall A Plugin In Cordova Project

Hi guys in this video we are going to learn how to install and uninstall a plugin in our cordova project.
#cordova 

Tutorial How to install and Uninstall A Plugin In Cordova Project