Flutter web app progress indicator before loading app? - flutter

Hi I am a mobile app developer and not much familiar with web development, I was finding any approach to implement Progress Indicator before loading the flutter web app like Gmail loading screen. Flutter web is cool but it takes few moments before loading the app. Can we add any indicator for this loading duration? Any code implemented in flutter would be the part of flutter app and it won't work, There should be another approach to achieve this.

With the help of #Abhilash, I was able to accomplish this. I got loader code from w3schools.
My project/web/index.html is like this.
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
<script defer src="index.dart.js" type="application/javascript"></script>
<style>
.loading {
display: flex;
justify-content: center;
align-items: center;
margin: 0;
position: absolute;
top: 50%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.loader {
border: 16px solid #f3f3f3;
border-radius: 50%;
border-top: 16px solid blue;
border-right: 16px solid green;
border-bottom: 16px solid red;
border-left: 16px solid pink;
width: 120px;
height: 120px;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
#-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
#keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<div class="loading">
<div class="loader"></div>
</div>
<script src="main.dart.js" type="application/javascript"></script>
</body>
</html>

In your question you mentioned
Any code implemented in flutter would be the part of flutter app and it won't work,...
I assume you tried to add the splash screen approach for android or IOS. Since flutter-web is simply an index.html and a couple of js files(for eg., main.dart.js), you should perhaps try the CSS loading animation trick. Since you didn't share any code I am not writing any code but the following would be my approach as explained by this red stapler video. He/she kindly provided a lot of CSS based animations here along with the codepen implementations for that.
So following would be my steps in the flutter_web_project\web\index.html file.
Add a span element in the body of index.html to show the css animation itself.
Create a div wrapper to position the span animation in your index.html.
Then listen to the onLoad event of the window and remove the div element from your page or fade it out as described in the video.

In addition to answer of #Shahzad Akram you should remove the loading div because in Safari browser it may cause of flickering. So in the first screen you need to implement the folowing code (for example, in initState method):
import 'package:universal_html/html.dart'
...
#override
void initState() {
super.initState()
// Remove `loading` div
final loader = document.getElementsByClassName('loading');
if(loader.isNotEmpty) {
loader.first.remove();
}
}
P.S. For nice loaders you can visit loading.io.

Adam's answer will remove loader before flutter is actually loaded.
I found this script to be the most complete answer:
<html>
<head>
<style>
.loading {
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
margin: 0;
position: absolute;
top: 50%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
.loader {
border: 8px solid #f3f3f3;
border-radius: 50%;
border-top: 8px solid #00AD87;
border-right: 8px solid #C30E48;
border-bottom: 8px solid #00AD87;
border-left: 8px solid #C30E48;
width: 60px !important;
height: 60px !important;
-webkit-animation: spin 2s linear infinite;
animation: spin 2s linear infinite;
}
#-webkit-keyframes spin {
0% {
-webkit-transform: rotate(0deg);
}
100% {
-webkit-transform: rotate(360deg);
}
}
#keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
</style>
</head>
<body>
<!-- First time loading -->
<div class="loading">
<div class="loader"></div>
</div>
<!-- Ensure first time loading progress is gone after app loads -->
<script>
window.addEventListener("flutter-first-frame", function() {
var element = document.getElementsByClassName("loading");
element[0].parentNode.removeChild(element[0]);
});
</script>
<script defer src="main.dart.js" type="application/javascript"</script>
</body>
</html>

If you want to remove loading div with just JS use this code
<script>
window.onload = (event) => {
console.log('page is fully loaded');
var element = document.getElementById("loader");
element.parentNode.removeChild(element);
};
</script>
Notice that it assumes that loader is a <div id="loader"></div> tag

In addition to answers from #Shahzad and #BambinoUA, I also needed to add defer keyword for main.dart.js script tag as well.
<script defer src="main.dart.js" type="application/javascript"></script>
Below is my scenario where this was needed:
app was hosted on Gitlab pages
browser was Chrome (with a slow internet)
In this case, only blank screen was visible until the whole script is downloaded. Then the animation was visible only for 0.5 second and flutter widgets loaded immediately after that. Thus failing the purpose of having loading animation. This doesn't happen in local testing.
I also tried putting the animation div before all scripts, but it didn't help.

I think the accepted answer is partially right as it's presented a loading indicator rather than a progress indicator. From flutter doc you can have a rough estimation of the flutter's actual loading progress. I've compiled an example using this indicator and it's showcased here.
Add this style
.container {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
width: 100%;
}
.progress-bar__container {
width: 80%;
height: 2rem;
border-radius: 2rem;
position: relative;
overflow: hidden;
transition: all 0.5s;
will-change: transform;
box-shadow: 0 0 5px #e76f51;
}
.progress-bar {
position: absolute;
height: 100%;
width: 100%;
content: "";
background-color: #e76f51;
top:0;
bottom: 0;
left: -100%;
border-radius: inherit;
display: flex;
justify-content: center;
align-items:center;
color: white;
font-family: sans-serif;
}
.progress-bar__text {
display: none;
}
and append this code on index.html of your flutter app.
function updateProgress(num) {
const progressBarContainer = document.querySelector('.progress-bar__container');
const progressBar = document.querySelector('.progress-bar');
const progressBarText = document.querySelector('.progress-bar__text');
let time = 0;
let endState = 100;
gsap.to(progressBar, {
x: num + "%",
duration: 2,
});
}
window.addEventListener('load', function(ev) {
var loading = document.querySelector('#loading');
loading.textContent = "Loading entrypoint...";
updateProgress(15);
_flutter.loader.loadEntrypoint({
serviceWorker: {
serviceWorkerVersion: serviceWorkerVersion,
},
onEntrypointLoaded: async function(engineInitializer) {
loading.textContent = "Initializing engine...";
updateProgress(50);
let appRunner = await engineInitializer.initializeEngine();
updateProgress(80);
loading.textContent = "Running app...";
await appRunner.runApp();
updateProgress(100);
}
});
});

During startup of a flutter web app, we have the 2 phases: the first phase is when the index.html page has already loaded but the actually flutter app is loading. Then when the flutter app is loaded, we still might need to do some preparation within the flutter app. I like both phases to show an indication of loading and I want this to be the same. So... what I did:
First my index.html displays a gif which shows a circular progress indicator similar to the one I have in flutter (see 2) loading.gif
I do this similar to what this person describes: https://retroportalstudio.medium.com/indicate-website-loading-for-flutter-web-apps-7dc5e2c59e24
Then in my flutter app, I show this indicator:
return Container(
decoration: BoxDecoration(color: Colors.white),
child: Center(child: CircularProgressIndicator())
);
This indicator is pretty much the same as the gif. I created this gif with a combination of https://gifcap.dev/ and gimp to crop it.
The result is a fairly smooth loading circular progress indicator almost instant upon opening my website all the way up to when my flutterweb app opens.

Related

Is there a way to have two ionic side menus active at the same time?

I'd like to achieve the following layout, in Ionic Vue, ideally using native components. Below is just a schema of what I want and I'm mostly interested in the desktop behavior:
Vue.createApp({
data: () => ({
isLeftOpen: false,
isRightOpen: false
}),
methods: {
toggleSidebar(side) {
this[`is${side}Open`] = !this[`is${side}Open`];
}
}
}).mount('#app')
body { margin: 0; overflow: hidden; }
* { box-sizing: border-box; }
#app {
height: 100vh;
background-color: #f5f5f5;
}
main {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
sidebar {
background-color: white;
display: block;
padding: 1rem;
width: 270px;
position: absolute;
top: 0;
bottom: 0;
transition: transform .21s cubic-bezier(.5,0,.3,1);
box-shadow: 0 1px 8px 0 rgb(0 0 0 / 20%), 0 3px 4px 0 rgb(0 0 0 / 14%), 0 3px 3px -2px rgb(0 0 0 / 12%);
}
sidebar[left] {
left: 0;
transform: translateX(-280px)
}
sidebar[right] {
right: 0;
transform: translateX(280px)
}
sidebar.open {
transform: translateX(0);
}
sidebar button {
width: 2rem;
height: 2rem;
position: absolute;
border-radius: 1rem;
border: 1px solid #f5f5f5;
right: .5rem;
top: .5rem;
cursor: pointer;
font-size: 1.5rem
display: flex;
align-items: center;
justify-content: center;
}
<script src="https://unpkg.com/vue#next/dist/vue.global.prod.js"></script>
<div id="app">
<main>
<button #click="toggleSidebar('Left')">left</button>
<button #click="toggleSidebar('Right')">right</button>
</main>
<sidebar left
:class="{open: isLeftOpen}">
Left sidebar
<button #click="toggleSidebar('Left')">×</button>
</sidebar>
<sidebar right
:class="{open: isRightOpen}">
Right sidebar
<button #click="toggleSidebar('Right')">×</button>
</sidebar>
</div>
In short, I want two sidebars completely unrelated, which should be opened/closed independently on all devices, according to user's choice. The argument that opening more than one sidebar at a time is not good UX doesn't really hold water on this project, as it's basically a full-screen map and the sidebars hold various controls and info about what's on the map. The requirement is that the user might want to have both sidebars open, but they might also want them both closed, even on big screens, to maximize the displayed portion of the map.
What options do I have here? To only have one "native" sidebar and mimic the second one with custom elements, using my own container and my own menu toggle resembling a native one? How would I make those look and behave as "native" on Android and iOS?
Here's my current layout, which achieves everything I want, except opening one sidebar always closes the other.
I don't know much about Ionic Vue (started using it today) but I'm decent in Vue. Tbh, I find Ionic Vue impressive. Very neat, documentation is stellar. But I'm stuck on this layout issue which seemed trivial at first.
Thanks for looking into this.

Ionic 2 Modal make 50% of the width

I have a page in my ionic application that on button click opens a Modal Page. Currently, I have override the variable.scss to the code below to make the model cover the 100% of the page.
//for Modals
$modal-inset-height-large: 100%;
$modal-inset-height-small: $modal-inset-height-large;
$modal-inset-width: 100%;
However, this applies for all my models in my application. I want to use some models in other pages that use the 50% of the width and around 80% of the height. How can I customize my controls?
You can not change a particular modal height or width.
Now, I will describe an solution which I use to resize my modal.
Ensured that all modal height and width should be 100%. As ionic
resize modal for large screen devices. That's why I added below code
in app.scss.
modal-wrapper {
position: absolute;
width: 100%;
height: 100%;
}
#media not all and (min-height: 600px) and (min-width: 768px) {
ion-modal ion-backdrop {
visibility: hidden;
}
}
#media only screen and (min-height: 0px) and (min-width: 0px) {
.modal-wrapper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}
Now In ion-content we make two div and the background of ion-content should be transparent (see main-view css class). Now, One div is used for background of the modal, this will use as backdrop (see overlay css class). Another div should be used for the content, we will resize this div (see modal-content css class).In example I resize the height to 50%. Sample html ans css code is given below,
page-about {
.main-view{
background: transparent;
}
.overlay {
position: fixed;
top: 0;
width: 100%;
height: 100%;
z-index: 1;
opacity: .5;
background-color: #333;
}
.modal_content {
position: absolute;
top: calc(50% - (50%/2));
left: 0;
right: 0;
width: 100%;
height: 50%;
padding: 10px;
z-index: 100;
margin: 0 auto;
padding: 10px;
color: #333;
background: #e8e8e8;
background: -moz-linear-gradient(top, #fff 0%, #e8e8e8 100%);
background: -webkit-linear-gradient(top, #fff 0%, #e8e8e8 100%);
background: linear-gradient(to bottom, #fff 0%, #e8e8e8 100%);
border-radius: 5px;
box-shadow: 0 2px 3px rgba(51, 51, 51, .35);
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
overflow: hidden;
}
}
<ion-content class="main-view">
<div class="overlay" (click)="dismiss()"></div>
<div class="modal_content">
<h2>Welcome to Ionic!</h2>
<p>
This starter project comes with simple tabs-based layout for apps that are going to primarily use a Tabbed UI.
</p>
<p>
Take a look at the <code>src/pages/</code> directory to add or change tabs, update any existing page or create new
pages.
</p>
</div>
</ion-content>
Here is a screen shot of the modal,
If you want modal content should scroll then replace <div class="modal_content"> with <ion-scroll class="modal_content" scrollY="true"> as told by Missak Boyajian in comment
For Ionic3 you need to this comment from Alston Sahyun Kim.
this is an excellent answer, just one thing from ionic3, .main-view{ background: transparent; } should be .content{ background: transparent; }
All the code is taken from here. I think this project repo will help you.
I tried before but had not found a generic way to make modals behave the way as I desired.
So I strugled a bit and achieved responsive modals and other kinds of modals with the following global scss:
ion-modal {
&.my-modal-inner {
display: flex;
align-items: center;
justify-content: center;
ion-backdrop {
visibility: visible;
}
.modal-wrapper {
display: flex;
align-items: flex-start;
justify-content: center;
overflow: auto;
width: auto;
height: auto;
left: auto;
top: auto;
contain: content;
max-width: 70%;
max-height: 70%;
border-radius: 2px;
box-shadow: 0 28px 48px rgba(0, 0, 0, 0.4);
> .ion-page {
position: relative;
display: block;
width: auto;
height: auto;
contain: content;
box-shadow: 0 28px 48px rgba(0, 0, 0, 0.4);
}
}
&.my-stretch {
.modal-wrapper {
overflow: hidden;
width: 100%;
height: 100%;
> .ion-page {
width: 100%;
height: 100%;
}
}
}
}
&.my-fullscreen {
.modal-wrapper {
position: absolute;
display: block;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}
}
You can have responsive modals that will have the size of the inner content using cssClass: 'my-modal-inner':
The modal will occupy at maximum 70% of the width and height (like defined in the above css) when the content surpasses the limit:
If the content of the modal is supposed to occupy all the container element (like a page or a component with ion-content), it will not work well with the above case because the modal supposes that the container should have the size of its children, causing a possibly undesired behaviour (the modal will be very small, more than it should):
Instead, you can define the modal to occupy its maximum size with cssClass: 'my-modal-inner my-stretch':
If you want the modal to be full screen, even in a large desktop browser, you can use cssClass: 'my-fullscreen':
Notes:
You can change the prefix my- with any other prefix of your choice (or no prefix).
You can change the maximum width and height of the modal in the above css, as you seem fit (I defined both as 70%, in your case it would be 50% and 80% for the width and height, respectively).
The above screenshots were taken in a desktop browser, but the modal changes also work in a mobile/native app with Ionic (I tested in Android, and it should work in iOS too).
Update (2018-07-30)
About the HTML codes for the modal:
1) Responsive modal that will be as large or as small as the inner content (a single div or a hierarchy of divs, spans and other block and inline elements should do):
<div class="main">
<div class="img-container">
<img src="assets/img/main/icon.png" [alt]="APP_NAME">
</div>
<div class="info-container">
<div class="app-name">{{ APP_NAME }}</div>
<div class="app-version">Version {{ APP_VERSION }}</div>
<div class="app-year">#{{ INITIAL_YEAR }}-{{ CURRENT_YEAR }} {{ APP_NAME }}</div>
<div class="app-rights">All rights reserved</div>
</div>
</div>
2) Modal will occupies its maximum size (use class my-stretch). In this case, any ionic page will do:
<ion-header>
<ion-navbar>
<ion-title>My Title</ion-title>
</ion-navbar>
</ion-header>
<ion-content>
<p> My content </p>
</ion-content>

jssor thumbnails disappear

I've looked and looked for what should be a simple answer, and for some reason I can't find it.
I'm experimenting with this amazing slider gleaned from the example here. I'd be happy if mine looked like this, considering that my slider has larger images.
When I reset the code to accommodate the larger images I lost the entire thumbnail panel and its black background. Obviously I also lost the thumbnail navigation.
You can see from my page that I've added a border. Regardless of the container size, the thumbnails have disappeared either way.
I would be grateful if someone points me to the code or js that deals with this. I would also appreciate if someone gave me some idea about the many selectors such as .jssora05r and .jssora05rdn, none of which have any html equivalent and leave me wondering what purpose they serve or whether they can just be omitted.
Please use class name to define css for slider1_container.
.slider1_container {
position: relative;
width: 960px;
height: 628px;
/*border: 20px solid #E1D9CC;*/
overflow: hidden;
/*margin: 90px auto 0;*/
margin: 0 auto;
padding-bottom: 0;
}
And remove the following codes,
#media only screen and ( max-width: 1152px ) {
.slider1_container {
max-width: 92%;
border-width: 15px;
}
}
#media only screen and ( max-width: 800px ) {
.slider1_container {
margin-top: 10px;
border-width: 10px;
max-width: 90%;
}
}
#media only screen and ( max-width: 640px ) {
.slider1_container {
border-width: 5px;
}
}
And also, jssor.js is missing in your code. Please replace
<script src="../js/jssor.slider.js" type="text/javascript"></script>
with
<script src="../js/jssor.js" type="text/javascript"></script>
<script src="../js/jssor.slider.js" type="text/javascript"></script>
Edit
<div id="slider1_container" class="slider1_container" ...
Move thumbnails
Slides are always in slides container. If you make slides container smaller than slider1_container, then you have rest space to place your thumbnail navigator. You can use css to set position of your thumbnailnavigator, for example
<div u="thumbnavigator" class="jssort01" style="left: 0px; bottom: 0px;">
Reference:
http://www.jssor.com/development/tip-arrange-layout-adjust-size.html
http://www.jssor.com/development/reference-ui-definition.html

How to make responsive clickable image/video like SagmeisterAndWalsh.com?

I want to make a responsive site that has an image with links you can click.
This site has invisible divs that sync up with the picture even as the image scales and resizes with the browser.
I want to first try to do the same thing with an image, and then I want to try it with a video.
Are they using any scss or javasript to make that happen, or are they just using css and html?
You can do it using just CSS and HTML, I've made a quick JSFiddle with a full size image background and a little nav.
As with the links you make the text on the image, then create a div ontop of them, don't set a background and just use a border until you get them in the correct place.
https://jsfiddle.net/2mow8qhv/2/
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<header id="bgHeader"></header>
<nav id="topNav">
Description | Gallery | Map |
Comments
</nav>
<div id="pageWrapper">
<div id="description">
<body>
</html>
/* Set all padding and margins to 0 by default, and colour to a grey unless overwritten*/
*{
padding: 0px;
margin: 0;
color: #333;
}
/* HEADER AND NAVIGATION*/
/* Sets a background image to fill 100% of the screen and fixes it in place*/
header#bgHeader{
background-image:url("http://seattlebubble.com/blog/wp-content/uploads/2014/11/Weyerhaeuser-Mansion_Tacoma.jpg");
background-size: cover;
background-position: center center;
background-attachment: fixed;
position:absolute;
width:100%;
height:100%;
}
/* Sets the navigation menu to the bottom of the page, and layered above the image*/
nav#topNav{
height: 60px;
width: 100%;
position: absolute;
bottom: 0px;
font-size: 1.5em;
line-height: 55px;
z-index: 2;
background: #000;
opacity: 0.7;
text-align: center;
}#topNav a{
text-decoration: none;
color: #FFF;
}#topNav a:hover{
color: #CCC;
}

change class attributes when hovering over other css class

I am trying to give a div with class "left2" a border-radius when class "left1_sub" is hovered.
I´ve searched a lot of solutions, but nothing seems to work for me.
The html to it: http://web318.login-11.hoststar.at/ben/kleinraum/wp/menuimg/index.html
and the full css: http://web318.login-11.hoststar.at/ben/kleinraum/wp/menuimg/style.css
.left1_sub{
padding-top:2%;
padding-bottom:2%;
width: 100%;
float: left;
background-color: #cccccc
}
.left1_sub:hover ~ .left2 {border-radius: 10px;}
.left2{
float: left;
margin-right: 20px;
margin-top: 20px;
width: 500px;
height:600px;
background-color: #ccccff
}
Just introducing myself to css3 so sorry if there are failures.
ben
This can be done very easily with jQuery or something similar.
If are comfortable using jQuery something like this would work.
First, create a class in CSS with a border radius:
.rounded { border-radius: 5px; /* (or whatever) */ }
Then, in <script> tags:
jQuery(document).ready(function($) {
var obj = $('.left1_sub'),
target = $('.left2');
obj.hover(
//mouse in
function(){
target.addClass('rounded');
//mouse out
},function(){
target.removeClass('rounded');
});
});
http://jsfiddle.net/wGzgB/11/