Implementing a Splash Screen, the wiser way

Implementing a Splash Screen, the wiser way

What is a Splash Screen?

A Splash Screen is basically a nice intro-screen that mobile applications have on startup of the app on a device. The splash screen can be customized according to the app’s UX need-animations, sound effects, etc. are some common tweaks to a simple splash screen.

I have been working with FOSSASIA on the Neurolab Android App where we made a splash screen for the same. Our implemented splash screen is below:

                                                     Neurolab Splash Screen

While developing this, we followed Google Material Design guidelines and the pattern it suggests is termed as ‘Launch Screen’. Displaying a launch screen can decrease the sense of long load time, and has the potential to add delight to the user experience. Launch screen implementation is considered as one of the best-practised development skills for a proper splash screen for an app.

Implementation 

Now, it is not a good idea to use a splash screen that wastes a user’s time. This should be strictly avoided. The right way of implementing a splash screen is a little different. In the new approach specify your splash screen’s background as the activity’s theme background. This way, we can effectively and efficiently use the time gap between the startup of the app and the onCreate() method.

In the Neurolab app, we use the splash screen as a bridge for the time gap between the app startup when we click the app icon and the onCreate method of the Neurolab Activity (Main/Launcher Screen) of the app, wherein the various UI components are laid out on the screen and the functionalities, navigations, listeners are linked to those components.

So, here we won’t be creating a new layout for the Splash screen as a separate activity. Rather we would specify the theme of the landing activity as the splash screen.

We create a drawable named splash_screen.xml in our project and give a parent tag of layer-list. Here is the code for our drawable file:

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:opacity="opaque">
    <item android:drawable="@android:color/white" />
    <item>
        <bitmap
            android:gravity="center_horizontal"
            android:src="@drawable/splash_image" />
    </item>
</layer-list>

Next, we are going to create a new theme in the styles resource file. This theme is going to be used as the base theme for the main activity screen of the app. In this style, we specify our created drawable file to the property name windowBackground.

<style name="AppTheme.Launcher">
        <item name="android:windowBackground">@drawable/splash_screen</item>
</style>

Then, update this style in the project manifest file to set the theme of the main activity

android:theme="@style/AppTheme.Launcher"

Having done the steps so far, we create a simple class extending the AppCompatActivity. Note- This may seem like another Activity screen, but it is not. We don’t specify the setContentView() here. Instead of this class just directs to the main/home activity using an Intent. Finally, be sure to finish() the SplashActivity activity (class) to remove prevailing unused/idle activities from back stack.

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Start landing activity screen
startActivity(new Intent(SplashActivity.this, MainActivity.class));
finish();
}

We are done!!

Launch your app, and observe your Launch screen. I can promise you that your “time won’t be wasted”(pun intended).

Thanks for reading. Hope this adds value to your Android application development skills. 

References:

Tags: FOSSASIA. Neurolab, GSOC19, Open-source, splash-screen, Android

Continue ReadingImplementing a Splash Screen, the wiser way

Integration of AliPay Payment Gateway using Stripe Sources

Image result for alipay logo svg

Integration of AliPay Payment Gateway using Stripe Sources

This blog post explains the process of how Stripe Sources has been leveraged to integrate AliPay to extend the payment options in China.

Stripe provides a plethora of payment options configurable with Sources

Source objects allow you to accept a variety of payment methods with a single API. A source represents a customer’s payment instrument, and can be used with the Stripe API to create payments. Sources can be charged directly, or attached to customers for later reuse.

Alipay is a push-based, single-use and synchronous method of payment. This means that your customer takes action to authorize the push of funds through a redirect. There is immediate confirmation about the success or failure of a payment.

   Workflow of Alipay on the backend

During the payment process, a Source API object is created and your customer is redirected to AliPay for authorization.

Payment Flow

  1. Create a Source Object with the parameters currency, redirect_url and amount.
  2. Create a page for completion of customer authorization by specifying the redirect_url.
  3. Change the source status from pending to chargeable.
  4. Confirm the payment by redirecting to the confirmation page and process the refund for any unsuccessful payments(if deducted)

Configuration Manager

Initially, we define a class named as AliPayPaymentsManager which handles the configuration of API keys and has methods to create source objects and make them chargeable.

class AliPayPaymentsManager(object):
    """
    Class to manage AliPay Payments
    """

    @staticmethod
    def create_source(amount, currency, redirect_return_uri):
        stripe.api_key = get_settings()['alipay_publishable_key']
        response = stripe.Source.create(type='alipay',
                                        currency=currency,
                                        amount=amount,
                                        redirect={
                                            'return_url': redirect_return_uri
                                        }
                                        )
        return response

    @staticmethod
    def charge_source(order_identifier):
        order = safe_query(db, Order, 'identifier', order_identifier, 'identifier')
        stripe.api_key = get_settings()['alipay_secret_key']
        charge = stripe.Charge.create(
                 amount=int(order.amount),
                 currency=order.event.payment_currency,
                 source=order.order_notes,
                 )
        return charge

                Methods to create & charge the source

The challenge of charging the source & redirection

After creating the source object, we need to make the source object chargeable. For this purpose, the user must be redirected to the external AliPay payment gateway page where the source object is authorized and its status is changed to chargeable. The main challenge to overcome here was the method in which the redirect link was attached to the object. The parameter _external is really crucial for this process as Flask would only recognize the url as an external url if this parameter is passed to url_for.

@alipay_blueprint.route('/create_source/<string:order_identifier>', methods=['GET', 'POST'])
def create_source(order_identifier):
    """
    Create a source object for alipay payments.
    :param order_identifier:
    :return: The alipay redirection link.
    """
    try:
        order = safe_query(db, Order, 'identifier', order_identifier, 'identifier')
        source_object = AliPayPaymentsManager.create_source(amount=int(order.amount), currency='usd',
                                                            redirect_return_uri=url_for('alipay_blueprint.alipay_return_uri',
                                                            order_identifier=order.identifier, _external=True))
        order.order_notes = source_object.id
        save_to_db(order)
        return jsonify(link=source_object.redirect['url'])
    except TypeError:
        return BadRequestError({'source': ''}, 'Source creation error').respond()

Route which creates the source and returns external redirection url

After the source object is created, the status changes to pending. To charge the user, the source object must become chargeable. For this, we need to redirect the user to an external page where the payment can be authorized and the source object can become chargeable.

External Authorization Page for AliPay

After authorizing the payment, we redirect to the url given in return_redirect_uri which is configured with the source object which tries to charge the source object as it is now chargeable. After this, a POST request is sent to the return_redirect_uri route which handles success and failure cases

@alipay_blueprint.route('/alipay_return_uri/', methods=['GET', 'POST'])
def alipay_return_uri(order_identifier):
    """
    Charge Object creation & Order finalization for Alipay payments.
    :param order_identifier:
    :return: JSON response of the payment status.
    """
    try:
        charge_response = AliPayPaymentsManager.charge_source(order_identifier)
        if charge_response.status == 'succeeded':
            order = safe_query(db, Order, 'identifier', order_identifier, 'identifier')
            order.status = 'completed'
            save_to_db(order)
            return redirect(make_frontend_url('/orders/{}/view'.format(order_identifier)))
        else:
            return jsonify(status=False, error='Charge object failure')
    except TypeError:
        return jsonify(status=False, error='Source object status error')

After AliPay authorization, the order is saved and payment is completed

Resources:

Related work and code repo:

Tags:

Eventyay, FOSSASIA, Flask, Ember.js, Open Event, Python, AliPay, Stripe

Continue ReadingIntegration of AliPay Payment Gateway using Stripe Sources

UNESCO Hackathon at FOSSASIA Summit 2019

As part of the celebration of the International Year of Indigenous Languages, the UNESCO and FOSSASIA once again joined hands in organizing a hackathon titled “Hack the Future”, aiming to preserve indigenous languages through free and open source software. The event took place from Mar 15 to Mar 17, during the FOSSASIA Summit 2019 at Lifelong Learning Institute, Singapore. The competition recorded a number of 193 registered participants from across Asia and neighboring regions. 15 projected ideas were submitted and 13 of them were pitched for 5 winning prizes.

The winning projects

For the expected outcome of the hack, the applications or games shall help to provide greater access to multilingual information and knowledge and enable knowledge-sharing and dissemination of good practices, specifically with regard to indigenous languages. All work shall be FOSS/Open Source and use or connect to FOSSASIA projects (APIs) and technologies to improve people’s lives and tackle indigenous languages and culture protection challenges.

The teams that met requirements and produced convincing solutions were:

  • Open Science Prize: Gadon
  • AI Dev Prize: Crowd-sourced Corpus Generation
  • Cloud Prize: Guageland
  • Indigenous Prize: Thazin
  • Audience Prize: Crowd-sourced Corpus Generation

Crowd Sourced Corpus Generation: the 5-member Indian hack team has built a crowd-sourced corpus generator that provides reliable crowd translations using AI matrix. The app contains of 2 major parts: (1) users’ translations input and (2) a platform where researchers and/or indigenous language experts can verify and give feedback on crowd translations.

Crowd-sourced Corpus Generation project team

Thazin is a mobile game project whose inspirations derived from flappy bird and Google Chrome’s “not connected” dinosaur game. In this game, a player needs to use particular indigenous languages to speak into the built-in microphone in order to get the bird to overcome obstacles of each level. The dataset is also generated from indigenous people themselves when they record their voices for players’ references.

Thazin project team

Gadong is another mobile game application designed to tackle the inadequacy of online resources for indigenous languages by providing a crowd-source dictionary for Khmu language. Gadon project not only aims to promote Khmu language to the public but also helps the Khmu people to learn English as a global language.

Gadong project team

GuageLand game application allows players to level up by learning and solving problems related to indigenous languages. The project is fully open source featuring technologies such as: SUSI.AI, react.js, node.js, Amazon-DynamoDB, html5, css3, javascript, NoSQL Database, PWA, and open data.

GuageLand project team

Participants, mentors and judges

The UNESCO Hackathon at FOSSASIA Summit 2019 received the participation of 193 candidates from 21 countries all over the world. Indians accounted for the largest number of participants (82), followed by Indians (62). And more than 20% of the participants were females.

Mentors

Seventeen open source advocates from Singapore, India, Vietnam, Sri Lanka, Germany, and indigenous experts from the Mekong region were invited to become mentors of the two-day hackathon. Mentors dedicatedly worked alongside with participants, giving them constructive feedback on the groups’ projects as well as showing them how to turn their ideas into feasible mobile app solutions. Some indigenous experts also joined the hacking projects as participants resulted in great diverse backgrounds of team members for each team.

Judges

The Hackathon jury consisted of UNESCO delegates, indegious languages experts and representatives from FOSSASIA, Microsoft, IBM, SUSI.AI and OpnTech. Some members from the jury board were mentors themselves. Thus, they not only provided support, made final evaluations on submitted projects but also encouraged participants to carry on their research after the  completion so that they can implement the applications into real life situations to empower the indeginous languages and culture through FOSS.

Conclusion

The event was another great achievement for both partners based on the quality of projects’ outcomes and the awareness of the concepts raised before, during and after the competition. With the support from UNESCO nominated indigenous experts, the young developers successfully developed innovative open source applications that support the dissemination of good practices with regard to indigenous languages and increase access to multilingual information and knowledge by leveraging open data and knowledge-sharing.

Links

Hackathon sessions at FOSSASIA Summit 2019: https://youtu.be/J53lT5IhkjY

FOSSASIA Summit 2019 Photos: https://photos.app.goo.gl/zrJnma6s1a1xPCu89

FOSSASIA on Twitter: https://twitter.com/fossasia

FOSSASIA Videos: https://www.youtube.com/fossasiaorg

FOSSASIA Calendar: https://calendar.fossasia.org



Continue ReadingUNESCO Hackathon at FOSSASIA Summit 2019

Open is Becoming the New Common Foundation across Business, Government, Science, and Industry

Interview with Shanker V Selvadurai, Vice President & Chief Technology Officer of Cloud and Cognitive Software for IBM Asia Pacific

Could you briefly introduce yourself?

I am Shanker Selvadurai and currently the Vice President & Chief Technology Officer of Cloud and Cognitive Software for IBM Asia Pacific. I am based in Singapore and lead the technical organization that helps clients across Asia Pacific to explore and co-create cloud-based solutions that leverage data, analytics and artificial intelligence (AI) capabilities to deliver better decisions and outcomes.

I joined IBM in 2006.  Prior to IBM, I held key leadership positions in areas of research, development, consulting, sales and marketing with technology companies like AT&T, NCR and Fujitsu as well as start-up BlueGill Technologies. During this period I lead teams varying in size from 6 to over 1,000 while being based in North America, Europe and Asia.

I have a Bachelor of Science degree and a Master of Business Administration. I am also an Open Group Certified Distinguished Architect. Besides having published international patents/papers, I have actively contributed to international technology standards committees that include the IFX Forum, OFX Consortium and the Microsoft Advisory Council. I was also an adjunct lecturer at the Singapore Management University, teaching courses related to Services Science and Advanced Business Technology.

Tell us about your session at the FOSSASIA Summit, what will you cover?

At the FOSSASIA Summit, I am participating in a panel on “Business, Government, Science – What Opportunities Does “Open” Bring to Society”.  I hope to share IBM’s involvement in the open source movement, how businesses like IBM benefit from open source, as well as share thoughts about approaching open contribution and open governance in the future.

Shanker V Selvadurai handing over IBM Cloud Prize for Hackathon Winners

Business, Government, Science – What Opportunities Does “Open” Bring to Society from your point of view?

Open is becoming the new common foundation across business, government, science, and industry today.  For example, companies that still compete head-to-head in the marketplace are coming together to collaborate in open source communities.  They contribute to open source software and use it in their own IT systems and applications. They gain a competitive advantage — even though they may be helping their competitors in the short run.  The data demonstrates that companies with open source programs see more benefits from open source code and community participation.

IBM Connecting with Open Source Community at FOSSASIA Summit
International IBM Team Participating in FOSSASIA Summit

What is the role of Free Open Source Software in cloud and AI solutions in IBM?

Our offering portfolio, especially for our growth initiatives such as cloud and AI, is based on a solid foundation of open technologies.  Most of our strategic initiatives are founded on open source projects or communities, and we work across a wide variety of internal stakeholders to ensure that that the contributions we make to the community also provide greater value to our clients.

IBM Training on Open Source Cloud and AI Technologies at FOSSASIA OpenTechSummit
Many Open Source Developers Connect with IBM At the Booth

What was your motivation to work for IBM and to participate in the FOSSASIA Summit?

IBM has a long history as a leader in, and supporter of open source communities, most notably in the Apache, Linux, and Eclipse Foundations.  I joined IBM to help continue this tradition and I am looking forward to discussing new ideas to help build the future of open source at FOSSASIA Summit.

Which FOSS projects in the area of cloud and AI can interested developers contribute in IBM? In which domains could you use some help?

IBM believes that communities with open governance and an inclusive philosophy will attract the largest ecosystems and markets.  For a listing of some of the top open source projects that IBM believes represent significant opportunity areas, I would like to share with information how IBM supports high-impact open source projects here.

Participants from Around the World Following IBM Keynote on FOSS Collaboration

Which new features can we expect in IBM cloud and AI this year? Do you plan to release any new projects as FOSS?

Most of our strategic initiatives today are founded on open source projects or communities (Cloud Native Computing, Hyperledger, CD Foundation, etc.), and we work across a wide variety of internal stakeholders to ensure that that the contributions we make to the community also provide greater value to our clients. For a specific example of open source innovation from IBM, please check out the Egeria Project, which was founded in part by IBM.

Shanker V Selvadurai with Panelists and FOSSASIA Founder Ms. Hong Phuc Dang at the Singapore Summit 2019

As well, at the FOSSASIA Summit in Singapore, IBM shares the “Call for Code Global Challenge, which IBM is the Founding Partner.  

This multi-year global initiative rallies developers to create practical, effective, and high-quality applications based on cloud, data, and artificial intelligence that can have an immediate and lasting impact on humanitarian issues.  Call for Code brings startup, academic, and enterprise developers together and inspires them to solve the most pressing societal issues of our time. Building on the success of the 2018 competition, the 2019 Call for Code Global Challenge again asks developers to create solutions that significantly improve preparedness for natural disasters and accelerate relief when they hit. This year’s challenge introduces an emphasis on individual health and community wellbeing. This includes solutions that can reduce the risk of disease, improve access to data and the availability of resources, and address the mental health needs of those impacted before, during, and after disasters.

Hands-on Training with IBM Cloud and AI Experts at FOSSASIA Summit
Hands-on Training with IBM Cloud and AI Experts at FOSSASIA Summit
Continue ReadingOpen is Becoming the New Common Foundation across Business, Government, Science, and Industry

10 Years FOSSASIA Anniversary OpenTechSummit 2019 Taking Place in Singapore

We are thrilled to update you with the amazing line-up at the 10 Years Anniversary Summit. The event is co-organized by the Lifelong Learning Institute and SkillsFuture under the theme “The Future is FOSS”.

Highlights of the FOSSASIA Anniversary Summit 2019 include:

  • Thu Mar 14 12:30 – Sun Mar 17 16:00 Exhibition: Showcases and job opportunities with tech companies and FOSS projects: Overview
  • Fri Mar 15 9:00 Cloud and AI Workshops: Join us for two intensive workshops with IBM experts from around the world on the latest technologies, development and deployment covering ‘Cloud, Containers and DevOps’ and developing ‘Machine Learning and Artificial Intelligence’ applications at the FOSSASIA Summit. Seats are limited. Sign up here.
  • Fri March 15 16:30 SUSI.AI – Create Skills for Your AI Solution: Sign up
  • Fri Mar 15 / Sat Mar 16 19:00 FOSSASIA Academy: Learn new tech skills in free introductory level technology workshops conducted with BuildingBloCS Computing students from Singapore. Topics include Introduction to Python, ML with Python, SQLite, MongoDB,  Vue.js, SUSI.AI Sign up to reserve.
  • Fri Mar 15 – Sun Mar 17 OpenTech Hackathon with UNESCO: Build open source apps and win prizes. Join Friday or Saturday.
  • Sat Mar 16 12:00 Capture the Community: Singapore Open Source Picture Taking and Birthday Cake. Join us
  • Sat Mar 16 13:30 Azure Kubernetes Service (AKS): Learn how to setup Kubernetes on Azure. Sign up here.
  • 12 Conference Tracks: Join talks by industry experts from IBM, Google, Oracle, Microsoft, Flowchain, Red Hat, Alibaba, Sysdig, Pivotal, Elastic, Codethink, Gitcoin and open source projects like VLC, Linux, CentOS, SELinux, Debian, Kubernetes, Lionsforge, Tensorflow, PostgreSQL, MySQL, FreeBSD, ReactJS, the Blockchain community as well as hardware experts from the Raspberry Pi Foundation, ARM, Bunnie Huang from Chibitronics, Mitch Altman and many more. We will be covering Conference Tracks such as AI, Blockchain and Cybersecurity: Schedule
  • Daily: Social Events: Pub crawls and city tours along with other techies from around the world! Sign up.

Meet companies, FOSS projects and communities and do hands-on workshops in the Exhibition:

  • Participate in workshops like doing experiments with Pocket Science Lab or Learn Soldering with Mitch Altman (Thu Mar 14 14:00, Fri Mar 15 14:00, Sat Mar 16, 14:00)
  • Get together with community developers and reps from Fosdem, CCC, Openfest, Linux Foundation, OSI and many companies and projects in the Hackers Lounge on Floor 1.
  • Exhibition Booths and Job Board: See showcases and find out about job opportunities from industry-leading companies and sponsors like IBM, UNESCO, Google, Indeed, Microsoft, Facebook, Flowchain, MySQL/Oracle, Singapore companies like Singapore Press Holdings and more: Overview 

Don’t miss out on our Social Events:

  • Sat Mar 16 19:00 10 Years FOSSASIA Party with Buffet, Live Music, Indian Dance, Chinese Performance & Cultural Program** : Celebrate FOSSASIA 10th Anniversary Party with us! Featuring Live Music, Cultural Highlights and Good Food! Indian dance, magic, music, Karaoke and so much more! (Social Event Tickets Required) : Tickets 
  • Wed Mar 13 15:00 FOSSASIA Meet & Greet: Join the FOSSASIA Speakers and Attendees Meet & Greet, meet the local tech scene, explore Singapore in a Culture and Exploration Wednesday Afternoon, and enjoy the taste of Asia at a local dinner: Attendance
  • Thu Mar 14 19:00 Welcome Dinner: With FOSSASIA Summit Speakers and Exhibitors: Attendence
  • Fri Mar 15 7:00 Cultural Morning Tour to Merlion Statue and View of Marina Bay: Attendence
  • Fri Mar 15 19:00 Chinatown & Clarke Quay Snacks and Pub Crawl: Network with speakers and participants of the FOSSASIA OpenTech Summit for a Chinatown and Clarke Quay Snacks an Pub Crawl on Friday Evening: Attendance
  • Sun Mar 17 20:30 Dim Sum and Midnight Hacks: Didn’t get enough of techie stuff? Want to work on this awesome project you found at FOSSASIA? Met some amazing developers at the weekend? Join us for the FOSSASIA After-Event hacking, coding, relaxing at Hackerspace.sg on Sunday evening: Attendance
  • Mon Mar 18 12:00 Community Lunch: Gather with us on Monday Noon for yummy local Singapore food: Attendance

FOSSASIA Summit – Schedule Roster


Featured Speakers and Sessions

We have more than 180 speakers and close to 200 sessions where participants can learn how to work with Cloud solutions, train their personal AI, create voice interfaces, build their own Operating Systems, create AR and VR apps for the web, learn about databases or prepare for Linux certification. Find out more about the speakers.


FOSSASIA Summit Theme: The Future is FOSS

Today we see that Free and Open Source is mainstream. The large online providers are offereing their services mainly based on FOSS solutions. FOSSASIA is part of a movement advancing FOSS to the next level developing not just software, but also Open Hardware like the Pocket Science Lab. The FOSS model provides us with a way to collaborate easily, freely and efficiently and it can help us to solve the problems of this planet together. Let’s do it at the FOSSASIA OpenTechSummit! The theme of the event is “The Future is FOSS”.


Thank you for sponsoring!

Thank you to our sponsors IBM, Google Open Source, Microsoft, Indeed.com, Flowchain, Facebook, MySQL/Oracle, SPH and partners for supporting the event!


Thank you for celebrating FOSSASIA’s 10th Anniversary with us.

Do follow us on our Social Media accounts to get the latest updates on the Summit and other Open Tech stuff.

We can’t wait to see you to share and gain techie knowledge with and from you!

Continue Reading10 Years FOSSASIA Anniversary OpenTechSummit 2019 Taking Place in Singapore

Reducing the YouTube response time by 90%

In this blog post, we are going to cover how the audio from Youtube is being used in SUSI Smart Speaker and how we reduced the response time from ~40 seconds to ~4 seconds for an average music video length.

First Approach

Earlier, we were using MPV player’s inbuilt feature to fetch the YouTube music. However, MPV player was a bulky option and the music server had to be started every time before initiating a music video.

video_process = subprocess.Popen([‘mpv’, ‘–no-video’, ‘https://www.youtube.com/watch?v=’ + video_url[4:], ‘–really-quiet’]) # nosec #pylint-disable type: ignore requests.get(‘http://localhost:7070/song/’ + video_url) self.video_process = video_process stopAction.run() stopAction.detector.terminate()

Making it Efficient

To reduce the response time, we created a custom Music Server based on Flask,python-vlc and python-pafy which accepts requests from the main client and instructs the System to play the music with just 90% more efficiency.

app = Flask(__name__)

Instance = vlc.Instance(‘–no-video’)

player = Instance.media_player_new()

url = @app.route(‘/song’, methods=[‘GET’])

def youtube():

    vid = request.args.get(‘vid’)

    url = ‘https://www.youtube.com/watch?v=’ + vid

    video = pafy.new(url)
    streams = video.audiostreams 

    best = streams[3]

    playurl = best.url

    Media = Instance.media_new(playurl)

    Media.get_mrl()

    player.set_media(Media)

    player.play()

    display_message = {“song”:“started”}

    resp = jsonify(display_message)

    resp.status_code = 200

    return resp

However, shifting to this Server removed the ability to process multiple queries and hence we were unable to pause/play/stop the music until it completed the time duration. We wanted to retain the ability to have ‘play/pause/stop’ actions without implementing multiprocessing or multithreading as it would’ve required extensive testing to successfully implement them without creating deadlocks and would’ve been overkill for a simple feature.

Bringing Back the Lost Functionalities

The first Step we took was to remove the vlc-python module and implement a way to obtain an URL that we use in another asynchronous music player.

@app.route(‘/song’, methods=[‘GET’])
def youtube():

    vid = request.args.get(‘vid’)

    streams = video.audiostreams

    best = streams[3]

    playurl = best.url 

    display_message = {“song”: “started”, “url”: playurl}

    resp = jsonify(display_message)

    resp.status_code = 200

    return resp

The next issue was to actually find a way to run the Music Player asynchronously. We used the `subprocess. Popen` method and cvlc to play the songs asynchronously.

try:

    x = requests.get(‘http://localhost:7070/song?vid=’ + video_url[4:])

    data = x.json()

    url = data[‘url’]

    video_process = subprocess.Popen([‘cvlc’, ‘http’ + url[5:], ‘–no-video’])

    self.video_process = video_process

except Exception as e:

    logger.error(e);

And this is how we were able to increase the efficiency of the music player while maintaining the functionalities.

References

Continue ReadingReducing the YouTube response time by 90%

Announcing the FOSSASIA Codeheat Winners 2018/19

We are very proud to announce our Grand Prize Winners and Finalist Winners of Codeheat 2018/2019.

Codeheat participants not only solved a stunning number of issues in FOSSASIA’s projects, reviewed pull requests, shared scrums, and wrote blog posts, but most importantly they encouraged and helped each other and collaborated across borders and cultures. More than 700 developers from 18 countries participated in the contest supported by 37 mentors. Over 2000 pull requests were merged. Thank you all for this amazing achievement!

With so many outstanding developers participating it was extremely difficult to decide the Grand Prize and Finalist Winners of the contest. Our winners stand out in particular as they contributed to FOSSASIA projects on a continuously high level following our Best Practices.

Each of the Grand Prize Winners is awarded a travel grant to join us at the FOSSASIA Summit in Singapore in March where they receive the official Codeheat award, and meet with mentors and FOSSASIA developers. Other Finalist Winners will receive travel support vouchers to go to a Free and Open Source Software event of their choice.

Congratulations to our Grand Prize Winners, Finalist Winners, and all of the participants who spent the last few of months learning, sharing and contributing to Free and Open Source Projects. Well-done! We are truly impressed by your work, your progress and advancement. The winners are (in alphabetical order):

Grand Prize Winners

Aakash S. Mallik
Harshit Khandelwal
Shubham Gupta

Finalist Winners

Aditya Srivastava
Samagra Gupta
Shridhar Goel
Shubham Kumar
Pranav Kulshrestha
Raj Vaibhav Dubey
Yogesh Sharma

About Codeheat

Codeheat is a contest that the FOSSASIA organization is honored to run every year. We saw immense growth this year in participants and the depth of contributions.

Thank you Mentors and Supporters

Our 40+ mentors and many project developers, the heart and soul of Codeheat, are the reason the contest thrives. Mentors volunteer their time to help participants become open source contributors. Mentors spend hundreds of hours during answering questions, reviewing submitted code, and welcoming the new developers to project. Codeheat would not be possible without their patience and tireless efforts. Learn more about this year’s mentors on the Codeheat website.

Certificate of Participation

Participating developers, mentors and the FOSSASIA admin team learnt so much and it was an amazing and enriching experience and we believe the learnings are the main take-away of the program. We hope to see everyone continuing their contributions, sharing what they have learnt with others and to seize the opportunity to develop their code profile with FOSSASIA. We want to work together with the Open Tech community to improve people’s lives and create a better world for all. As a participating developer or mentor, you will receive your certificate over the upcoming weeks. Thank you!

More Links

Continue ReadingAnnouncing the FOSSASIA Codeheat Winners 2018/19

Integrating Redux with SUSI.AI Web Clients

In this blog post, we are going to go through the implementation of the Redux integration on the SUSI.AI web clients. The existing SUSI.AI WebChat codebase has Flux integrated into it, but integrating Redux would make it a lot easier to manage the app state in a single store. And would result in a more maintainable and performant application. Let us go through the implementation in the blog –

The key steps involved the following –

  • Restructuring the directory structure of the repository to enable better maintenance.
  • Creating a Redux store and configuring the middlewares.
  • Standardizing the format for writing actions and make API calls on dispatching an action.
  • Standardizing the format for writing reducers.
  • Hook the components to the Redux store.

Restructuring the directory structure

DIrectory structure for https://chat.susi.ai
  • All the redux related files and utils are put into the redux directory, to avoid any sort of confusion, better maintenance and enhanced discoverability. The prime reason for it also because the integration was done side-by-side the existing Flux implementation.
  • The actions and reducers directory each has a index.js, which exports all the actions and reducers respectively, so as to maintain a single import path for the components and this also helped to easily split out different types of actions/reducers.

Creating Redux store and configure middlewares

import { createStore as _createStore, applyMiddleware } from 'redux';
import { routerMiddleware } from 'react-router-redux';
import reduxPromise from 'redux-promise';
import reducers from './reducers';

export default function createStore(history) {
 // Sync dispatched route actions to the history
 const reduxRouterMiddleware = routerMiddleware(history);
 const middleware = [reduxRouterMiddleware, reduxPromise];

 let finalCreateStore;
 finalCreateStore = applyMiddleware(...middleware)(_createStore);

 const store = finalCreateStore(
   reducers,
   {},
   window.__REDUX_DEVTOOLS_EXTENSION__ &&
     window.__REDUX_DEVTOOLS_EXTENSION__(),
 );

 return store;
}
  • The function createStore takes in the browserHistory (provided by React Router) and returns a single store object that is passed on to the entry point component of the App.
  • The store is passed to the application via the <Provider> component, provided by the react-redux. It is wrapped to the <App> component as follows –

ReactDOM.render(
 <Provider store={store} key="provider">
   <App />
 </Provider>,
 document.getElementById('root'),
);
  • The 2 middlewares used are routerMiddleware provided by the react-router-redux and the reduxPromise provided by redux-promise.
  • The routerMiddleware enhances a history instance to allow it to synchronize any changes it receives into application state.
  • The reduxPromise returns a promise to the caller so that it can wait for the operation to finish before continuing. This is useful to assist the application to tackle async behaviour.

Standardizing the actions and making API calls on action dispatch

  • The actions file contains the following –

import { createAction } from 'redux-actions';
import actionTypes from '../actionTypes';
import * as apis from '../../apis';

const returnArgumentsFn = function(payload) {
 return Promise.resolve(payload);
};

export default {
// API call on action dispatch
 getApiKeys: createAction(actionTypes.APP_GET_API_KEYS, apis.fetchApiKeys),
// Returns a promise for actions not requiring API calls
 logout: createAction(actionTypes.APP_LOGOUT, returnArgumentsFn),
};

  • As new actions are added, it can be added to the actionTypes file and can be added in the export statement of the above snippet. This enables very standard and easy to manage actions.
  • This approach allows to handle both types of action dispatch – with and without API call. In case of API call on dispatch, the action resolves with the payload of the API.
  • The APIs are called via the AJAX helper (Check out this blog – https://blog.fossasia.org/make-a-helper-for-ajax-requests-using-axios/ ).

Standardizing the reducers and combining them

  • The reducers file contains the following –

import { handleActions } from 'redux-actions';
import actionTypes from '../actionTypes';

const defaultState = {
 ...
 apiKeys: {},
 ...
};

export default handleActions({
  [actionTypes.APP_GET_API_KEYS](state, { payload }) {
     const { keys } = payload;
     return {
       ...state,
       apiKeys: { ...keys },
     };
  },
  ...
},defaultState);
  • The default application state is defined and the reducer corresponding to each action type returns an immutable object which is the new application state,
  • In the above example, the payload from the getApiKeys API call is received in the reducer, which then updated the store.
  • The reducers/index.js  combines all the reducers using combineReducers provided by redux and exports a single object of reducers.

import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
import app from './app';
import settings from './settings';
import messages from './messages';

export default combineReducers({
 routing: routerReducer,
 app,
 settings,
 messages,
});

Hook the components to the Redux store

  • After Redux integration and standardization of the reducers, actions, any of the component can be hooked to the store as follows –

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';

class MyComponent extends Component {
 componentDidMount() {
    // Dispatch an action
    this.props.actions.getApiKeys();
 }
 render() {
   const { apiKeys } = this.props;
   return (
     <div>
        /* JSX */
     </div>     
   );
 }
}

function mapStateToProps(store) {
 const { apiKeys } = store.app;
 return {
   apiKeys
 };
}

function mapDispatchToProps(dispatch) {
 return {
   actions: bindActionCreators(actions, dispatch),
 };
}

export default connect(mapStateToProps, mapDispatchToProps)(MyComponent);
  • The mapStateToProps is a function that is used to provide the store data to the component via props, whereas mapDispatchToProps is used to provide the action creators as props to the component.

The above was the implementation of Redux in the SUSI.AI Web Clients. I hope the blog provided a detailed insight of how Redux was integrated and the standards that were followed.

References

Continue ReadingIntegrating Redux with SUSI.AI Web Clients

Make a helper for AJAX requests using axios

In this blog post, we are going to go through the implementation of the helper function that is created for making AJAX requests using axios. Currently, the AJAX calls are made in a very random manner where the calls are written in the component itself and involves rewriting of headers, etc for the API call. Let us go through the implementation in the blog, which will standardise the way to make API calls in SUSI.AI web clients.

The primary changes are –

  • Making a common helper for AJAX requests with the help of axios.
  • Making a common file containing all the API calls across the project.

Going through the implementation

The API calls within the repository were not being made in an organised way, also a lot of redundant code was present. The aim of creating the helper is that, all the API calls is called via this common function. It takes care of the headers and also sending access_token with the API if the user is already logged in for API calls requiring authentication. The function for a API request now looks this simple –

// API call for signup
export function getSignup(payload) {
 const { email, password } = payload;
 const url = `${API_URL}/${AUTH_API_PREFIX}/signup.json`;
 return ajax.get(url, { signup: email, password });
}
  • In the above snippet, the ajax is the common helper used for making API calls. ajax is an object of functions that returns a promise for  various methods of API requests
  • We have primarily taken into consideration GET & POST requests type.
  • The helper function is as follows –
/* Insert imports here*/
const cookies = new Cookies();
const obj = {};

['get', 'post', 'all'].forEach(function(method) {
 obj[method] = function(url, payload, settings = {}) {
   /* Request will be aborted after 30 seconds */
   settings = {
     timeout: 30000,
     dataType: 'json',
     crossDomain: true,
     ...settings,
   };
   
   // Check if logged in
   if (cookies.get('loggedIn')) {
     payload = {
       access_token: cookies.get('loggedIn'),
       ...payload,
     };
   }

   return new Promise(function(resolve, reject) {
     let methodArgs = [];
     if (method === 'post') {
       if (payload && payload instanceof FormData !== true) {
           // Convert to Form Data
           payload = toFormData(payload);
       }

       settings.headers = {
         'Content-Type': 'application/x-www-form-urlencoded',
         ...settings.headers,
       };
     } else if (method === 'get') {
       if (payload) {
         // Add params to the URL   
         url += `?${Object.keys(payload)
           .map(key => key + '=' + payload[key])
           .join('&')}`;
       }
     }

     const methodsToAxiosMethodsMap = {
       get: 'get',
       post: 'post',
       all: 'all',
     };

     if (method === 'all') {
       methodArgs = [url];
     } else if (method === 'get') {
       methodArgs = [url, settings];
     } else {
       methodArgs = [url, payload, settings];
     }

     axios[methodsToAxiosMethodsMap[method]].apply({}, methodArgs).then(
       function(data = {}, ...restSuccessArgs) {
         const statusCode = _.get(data, 'status');
         /*  Send only api response */
         let responseData = { statusCode, ..._.get(data, 'data') };

         if (method === 'all') {
           responseData = data;
           responseData.statusCode = statusCode;
         }

         if (payload) {
           responseData.requestPayload = payload;
         }
         // Mark the promise resolved and return the payload
         resolve(camelizeKeys(responseData), ...restSuccessArgs);
       },
       function(data = {}, ...restErrorArgs) {
         // If request is canceled by user
         if (axios.isCancel(data)) {
           reject(data);
         }

         const statusCode = _.get(data, 'response.status', -1);
         let responseData = { statusCode, ..._.get(data, 'response.data') };

         if (method === 'all') {
           responseData = data;
           responseData.statusCode = statusCode;
         }

         if (payload) {
           responseData.requestPayload = payload;
         }
         // Mark the promise rejected and return the payload
         reject(camelizeKeys(responseData), ...restErrorArgs);
       },
     );
   });
 };
});

export default obj;
  • The above objects contains 3 functions –
    • ajax.get(url, payload, settings) – GET – The helper adds the query params to the URL by iterating through them and appending it to the URL and joining them with &.
    • ajax.post(url, payload, settings) –  POST – The helper checks, if the POST requests contains a payload which is an instance of form data, it converts to toFormData payload.
    • ajax.all(url, payload, settings) – ALL – It helps to deal with concurrent requests.
  • The url is the complete API endpoint, payload consists of the data/request payload. The settings consists of any headers related info, that needs to be added exclusively to the axios config.
  • There is also no need to pass access token to each API request as a payload. The helper check whether the user is logged-in and adds the access_token to the request payload. The snippet below demonstrates it –
if (cookies.get('loggedIn')) {
     payload = {
       access_token: cookies.get('loggedIn'),
       ...payload,
     };
   }
  • The access token, if present in the cookies is added to the payload, therefore authenticating the API call.
  • The keys of the response are changed to camel case before being sent to the caller function. It is done to maintain variable nomenclature standards across the app and also to follow javascript guidelines.
  • The file containing the API calls is structured as follows –
import ajax from '../helpers/ajax';
import urls from '../utils/urls';

const { API_URL } = urls;
const AUTH_API_PREFIX = 'aaa';
const CHAT_API_PREFIX = 'susi';
const CMS_API_PREFIX = 'cms';

// API without request payload
export function fetchApiKeys() {
 const url = `${API_URL}/${AUTH_API_PREFIX}/getApiKeys.json`;
 return ajax.get(url);
}

// API with request payload
export function getLogin(payload) {
 const { email, password } = payload;
 const url = `${API_URL}/${AUTH_API_PREFIX}/login.json`;
 return ajax.get(url, { login: email, password, type: 'access-token' });
}

The above was the implementation of the helper function that is created for making AJAX requests using axios. I hope the blog provided a detailed insight of it helps in making the process of making API calls more standardised and easier.

References

Continue ReadingMake a helper for AJAX requests using axios

Adding 3D Home Screen Quick Actions to SUSI iOS App

Home screen quick actions are a convenient way to perform useful, app-specific actions right from the Home screen, using 3D Touch. Apply a little pressure to an app icon with your finger—more than you use for tap and hold—to see a list of available quick actions. Tap one to activate it. Quick actions can be static or dynamic.

We have added some 3D home screen quick action to our SUSI iOS app. In this post, we will see how they are implemented and how they work.

The following 3D home screen quick actions are added to SUSI iOS:

  • Open SUSI Skills – user can directly go to SUSI skills without opening a chat screen.
  • Customize Settings – user can customize their setting directly by using this quick action.
  • Setup A Device – when the user quickly wants to configure his/her device for SUSI Smart Speaker, this is quick action is very helpful in that.
  • Change SUSI’s Voice – user can change SUSI message reading language accents directly from this quick action.

Each Home screen quick action includes a title, an icon on the left or right (depending on your app’s position on the home screen), and an optional subtitle. The title and subtitle are always left-aligned in left-to-right languages.

Step 1 – Adding the Shortcut Items

We add static home screen quick actions using the UIApplicationShortcutItems array in the app Info.plist file. Each entry in the array is a dictionary containing items matching properties of the UIApplicationShortcutItem class. As seen in screenshot below, we have 4 shortcut items and each item have three properties UIApplicationShortcutItemIconType/UIApplicationShortcutItemIconFile, UIApplicationShortcutItemTitle, and UIApplicationShortcutItemType.

  • UIApplicationShortcutItemIconType and UIApplicationShortcutItemIconFile is the string for setting icon for quick action. For the system icons, we use UIApplicationShortcutItemIconType property and for the custom icons, we use UIApplicationShortcutItemIconFile.
  • UIApplicationShortcutItemTitle is a required string that is displayed to the user.
  • UIApplicationShortcutItemType is a required app specific string used to identify the quick action.

Step 2 – Handling the Shortcut

AppDelegate is the place where we handle all the home screen quick actions. We define these variables:

var shortcutHandled: Bool!
var shortcutIdentifier: String?

When a user chooses one of the quick actions the launch of the system or resumes the app and calls the performActionForShortcutItem method in app delegate:

func application(_ application: UIApplication,
                     performActionFor shortcutItem: UIApplicationShortcutItem,
                     completionHandler: @escaping (Bool) -> Void) {
        shortcutIdentifier = shortcutItem.type
        shortcutHandled = true
        completionHandler(shortcutHandled)
    }

Whenever the application becomes active, applicationDidBecomeActive function is called:

func applicationDidBecomeActive(_ application: UIApplication) {
        // Handel Home Screen Quick Actions
        handelHomeActions()
    }

Inside the applicationDidBecomeActive function we call the handleHomeAction() method which handles the home screen quick action.

func handelHomeActions() {
       if shortcutHandled == true {
           shortcutHandled = false
           if shortcutIdentifier == ControllerConstants.HomeActions.openSkillAction {
               // Handle action accordingly
               }
           } else if shortcutIdentifier == ControllerConstants.HomeActions.customizeSettingsAction {
               // Handle action accordingly
           } else if shortcutIdentifier == ControllerConstants.HomeActions.setupDeviceAction {
               // Handle action accordingly
               }
           } else if shortcutIdentifier == ControllerConstants.HomeActions.changeVoiceAction {
               // Handle action accordingly
               }
           }
       }
   }

Final Output:

Resources –

  1. Home Screen Quick Actions – Human Interface Guidelines by Apple
  2. Adding 3D Touch Quick Actions by Use Your Leaf
  3. Apple’s documentation on performActionFor:completionHandler
Continue ReadingAdding 3D Home Screen Quick Actions to SUSI iOS App