Ionic discards changes in global css variable after closing the app - css

I want to enable my users to set certain global colors when using the app. Therefor I have created a 'dynamicVariables.css' file:
:root {
--my-color: violet;
}
It is imported in 'global.scss' file:
#import "./theme/dynamicVariables.css";
Also, I've added a colorpicker on one page and I can set the --my-color variable fine from there.
onColorChange(data: any) {
document.documentElement.style.setProperty('--my-color', data);
}
Just when closing the app on my device (I've deployed it with ionic capacitor run android), it resets the css variable, because when I run it again the color is back to its default value.
I'm pretty sure, I have a general misconception here and would be grateful for some clarification. I'm generally new to web development and would be grateful for any help.
Thanks in advance.

just like how Mustafa explained in comments, you need to make these changes outside app "runtime" and in the device's memory, that would stay there even after the app (whether web or native) is closed. for example you can use ionic storage and save your data with keys and values same as your css keys, and load it up whenever the app opens.

Thanks to the responds, I was able to solve the problem with the help of Ionic Storage.
First, I created a Storage Service:
import { Storage } from '#ionic/storage-angular';
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class StorageService {
private _storage: Storage | null = null;
constructor(private storage: Storage) {
}
async init() {
const storage = await this.storage.create();
this._storage = storage;
}
public set(key: string, value: any) {
this._storage?.set(key, value);
}
public get(key: string) {
return this._storage?.get(key);
}
}
When starting the app, I run the following code in the app.component.ts
async ngOnInit() {
await this.storageService.init();
let storedPathologicalColor = await this.storageService.get('--my-color');
if (storedPathologicalColor == null)
document.documentElement.style.setProperty('--my-color', getComputedStyle(document.documentElement).getPropertyValue('--my-color'))
else
document.documentElement.style.setProperty('--my-color', storedPathologicalColor);
}
It is important to init() the service from outside. When setting a new css variable, I also set a new key/value pair to the Storage.
Thanks again.

Related

Firebase makes unity hang

I wanted to user firestore in my unity proyect, so I did as in the documentation. Notice that I also do db = FirebaseFirestore.DefaultInstance;.
I put the firebase starting code in a trial monobehviour in of my scene, in which I wanted to make some database query trials.
Firebase.FirebaseApp app;
void Start() {
Firebase.FirebaseApp.CheckAndFixDependenciesAsync().ContinueWith(task => {
var dependencyStatus = task.Result;
if (dependencyStatus == Firebase.DependencyStatus.Available) {
// Create and hold a reference to your FirebaseApp,
// where app is a Firebase.FirebaseApp property of your application class.
app= Firebase.FirebaseApp.DefaultInstance;
Debug.LogError("FirebaseApp succesfully created");
// Set a flag here to indicate whether Firebase is ready to use by your app.
} else {
UnityEngine.Debug.LogError(System.String.Format(
"Could not resolve all Firebase dependencies: {0}", dependencyStatus));
// Firebase Unity SDK is not safe to use here.
}
});
db = FirebaseFirestore.DefaultInstance;
}
Every time I stopped my app and re-played in the editor, unity freezed, and I had to kill the process and restart unity.
Since I commented out the: app= Firebase.FirebaseApp.DefaultInstance;
to: //app= Firebase.FirebaseApp.DefaultInstance; as I only wanted to use the database, everything is going fine.
Am I doing something wrong? Does it make sense that due to some mistake unity hangs after re-play (first play works).
On the other hand I dont understand why in the docs the code advices to store the FirebaseApp in a variable if the FirebaseApp class has got an static instance getter: public static FirebaseApp DefaultInstance { get; }
Thanks for any comment.

HOCs, Context API and Next Pages

Its possible to use Hoc with context api inside a next page?
I have a next page generated by SSR, and a HOC privateRoute to validate authorization on this page. But for every access, we have a authorization request and its sound's me like a problem.
My idea is to use contexApi to get data one time, and reuse that on auth private route.
Anyone has a minimal exemple about?
Thanks.
I found a solution.
The problem was to use Context inside react class component.
mport React, { Component } from 'react'
import UserContext from './UserContext'
class HomePage extends Component {
static contextType = UserContext
componentDidMount() {
const user = this.context
console.log(user) // { name: 'Tania', loggedIn: true }
}
for more, see https://www.taniarascia.com/using-context-api-in-react/
render() {
return <div>{user.name}</div>
}
}

Firebase cloud function change event timestamps wrong

we are building a system where changes in Firestore produce PubSub-message on which other components may act.
Firestore events are used to implement this. The system keeps a history of changes for each document as subcollection of the document. To reduce the size of the PubSub-messages we are only sending references to documents in this subcollection. One before and one after the change. To allow our function to not waste time with queries to figure out what the last state was we are using the timestamps on the change events as ids.
env.ts:
import * as functions from 'firebase-functions';
import {handler} from '#handlers/rootCollection';
//noinspection JSUnusedGlobalSymbols
export const handlerFunction = functions.firestore
.document('rootcollection/{documentID}')
.onWrite(handler.process.bind(handler));
rootCollection.ts:
import {DocumentSnapshot} from 'firebase-functions/lib/providers/firestore';
import {Change, EventContext} from 'firebase-functions';
interface MessageI extends Object {
eventID: string;
ref: string;
beforeID: string | null;
afterID: string | null;
fcfReceived: number | null;
}
class WriteHandler {
public name: string;
public constructor(name: string) {
this.name = name;
}
public async process(change: Change<DocumentSnapshot>, context: EventContext): MessageI {
const afterExists = change.after.exists;
const beforeExists = change.before.exists;
const afterID = afterExists ? change.after.updateTime.toMillis().toString() : null;
const beforeID = beforeExists ? change.before.updateTime.toMillis().toString() : null;
return {
'eventID': context.eventId,
'ref': change.before.ref.path,
'beforeID': beforeID,
'afterID': afterID,
'fcfReceived': Date.now()
};
}
}
export const itinerariesHandler = new WriteHandler(
'rootCollectionHandler'
);
Now we are pretty surprised that the data is correctly reflecting the before and after states but the timestamp seems to be the after.timestamp.
Published message 429345402459000 to topic. Message:
{
"eventID": "389fe158-115a-43ca-9fdd-ec9737af066f-0",
"ref": "collection/VMDcsHirbB2coyaXF5wZ",
"beforeID": "1552298315479",
"afterID": "1552298315479",
"fcfReceived": 1552298315575,
}
It seems counterintuitive that change.before.updateTime is containing the time when the change was done. But i cannot find a explicit mention in the documentation.
Is this behavior intended? Is there another way to find a unique id for the before state?
Regards,
Carsten
firebaser here
This is bug in the Firestore bindings for Cloud functions. It indeed sets the before.updateTime and after.updateTime to the same value.
We filed a bug internally to get this fixed. But there is no timeline for when this fix will be available.
Until that time the best I can think of is to add an lastUpdated field to the document data, and validate that is the current server-side timestamp in your security rules. That way you can get the before.data().lastUpdated and after.data().lastUpdated to do the comparison. This should at least allow you to implement the behavior, until the problem is fixed.

React Native persisting user data

In my app I have 2 components (Page and Home).
Home extends Page like so:
export default class Home extends Page
and Page just extends Component.
In Page I have a method to get user data from AsyncStorage
async getUser() {
// get from storage
this.setState({user});
}
The above is called on the constructor of Page.
The problem I have is that Home has a method on componentWillMount that relies on this.state.user. Obviously this isn't going to work since the getUser method is async.
Is there a way I can get the user information and only call specific methods once I have that info?
export default class Page extends Component {
async getUser() {
// get from AsyncStorage
this.setState({user});
}
componentWillMount() {
this.getUser();
}
}
export default class Home extends Page {
async foo(user_id) {
this.setState({something});
}
componentWillMount() {
this.foo(this.state.user);
}
render() {
return <Text>{this.state.something}</Text>;
}
}
Is there a way I can get the user information and only call specific
methods once I have that info?
Not in a general sense, but of course there are some solutions. What this comes down to is that you have an async data dependency. You need to write the code in such a way that a call to dependent functions is only made after the data becomes available.
Perhaps the easiest way to do this is to use componentWillUpdate instead of componentDidMount and check if you are receiving the required data:
componentWillUpdate(nextProps, nextState) {
if (nextState.user != null && this.state.user !== nextState.user) {
this.prepareForUser(nextState.user);
}
}
(Note that you can't setState directly in componentWillUpdate, but since your method is async it won't happen until later. You can use componentDidUpdate to chain another setState call.)
Another option (which I like to use) is to use composition instead of inheritance. This makes the life-cycle easier to control through rendering: the parent can only render a child when all the child's dependent data is loaded, then the child does not need to worry about any timing issues related to the initial loading of data and can do whatever it wants from its componentDidMount:
class UserContainer extends Component {
state = {};
componentDidMount() {
this.getUser();
}
async getUser() {
// get user from async store
this.setState({user});
}
render() {
return (
<div>
{ this.state.user ? <UserView user={this.state.user} /> : <Spinner /> }
</div>
);
}
}
class UserView extends Component {
componentDidMount() {
this.props.user != null
}
}
This is pretty much the "container component" pattern.

Exporting a TypeScript module results in interfaces not getting picked up

I'm using TypeScript and SignalR together, and am trying to define static types for the generated SignalR classes. And if I do something like this, it works:
///<reference path="../Scripts/jquery-1.8.d.ts" />
///<reference path="../Scripts/signalr-1.0.d.ts" />
interface SignalR {
roomHub: Service.RoomHub;
}
module Service {
export var roomHub = $.connection.roomHub;
export interface RoomHub { }
}
And of course $.connection is of type SignalR, which is defined in the file "signalr-1.0.d.ts", and extended in the file above.
However, I need to be able to reference the Service module from other files, so I need to add the "export" keywords to both the module and the interface, i.e.:
///<reference path="../Scripts/jquery-1.8.d.ts" />
///<reference path="../Scripts/signalr-1.0.d.ts" />
export interface SignalR {
roomHub: Service.RoomHub;
}
export module Service {
// Error here: "The property 'roomHub' does not exist on type SignalR."
export var roomHub = $.connection.roomHub;
export interface RoomHub { }
}
However, when I do that, I get a little red squiggly line under $.connection.roomHub, and the compiler returns the error, "The property 'roomHub' does not exist on type SignalR."
I certainly don't understand everything about TypeScript, but that doesn't seem right to me. Have I run into a compiler bug? Or is there a different way to do this?
I was able to figure out a workaround. I pulled out the interfaces into a separate file:
// File: ISignalR.ts
interface SignalR {
roomHub: RoomHub;
}
interface RoomHub {
}
And then I referenced that file in my Service file
///<reference path="../Scripts/jquery-1.8.d.ts" />
///<reference path="../Scripts/signalr-1.0.d.ts" />
///<reference path="ISignalR.ts" />
export module Service {
export var roomHub = $.connection.roomHub;
}
And that works, oddly enough. I'm not sure if it's a compiler bug, or something I'm continuing to misunderstand, but it clearly has something to do with some subtle semantic changes related to the AMD module support. I'd love to hear more of an explanation from someone who groks TypeScript and/or RequireJS modules a little better than I do.
If the SignalR object has actual members, you want to use the declare module syntax instead. interface declarations only describe members on types (rather than describing extant objects).
///<reference path="../Scripts/jquery-1.8.d.ts" />
///<reference path="../Scripts/signalr-1.0.d.ts" />
declare module SignalR {
var roomHub: Service.RoomHub;
}
export module Service {
// Good now
export var roomHub = $.connection.roomHub;
export interface RoomHub { }
}
There is more than one way to wire SignalR up, and using createHubProxy and invoke are more TypeScript friendly:
export class FrameworkHub {
private connection: HubConnection;
private proxy: HubProxy;
Init(): void {
this.Connected = false;
this.connection = $.hubConnection();
this.connection.logging = true;
// Binding with createHubProxy means you can use a string name, so no need to add dynamic properties to the hub
this.proxy = this.connection.createHubProxy("MyHubName");
this.wireEventListeners();
this.initializeConnection();
}
// Binding with proxy.on means you can use a string name for the function, so no need to add dynamic properties to the hub.
wireEventListeners(): void {
this.proxy.on("HandleFrameworkMessage", (message: IFrameworkMessage) => {
console.log("HandleFrameworkMessage: " + message.AccountID + " - " + message.ArmID);
// Do something to handle the message here.
});
}
initializeConnection(): void {
//console.log("Framework Hub initializeConnection");
var that = this;
//Again, using invoke means passing a string argument.
this.connection.start().done(() => {
that.proxy.invoke("Connect", this.AccountID, this.ArmID).done((response:FrameworkHubResponse) => {
//console.log("FHR: " + response.Success + " - " + response.Message);
if (response.Success) {
// Do something.
}
else {
// Try again. Would be better with some kind of exponential back-off.
setTimeout(that.initializeConnection, 500);
}
});
});
}
}
That's a slightly rough example cut from real code, but I've found it the best TS way to use SignalR. Docs for this kind of connection are here: https://github.com/SignalR/SignalR/wiki/SignalR-JS-Client-Hubs-%28No-Proxy%29 - watch out because the Docs haven't always kept pace with the recent changes.

Resources