So I have created a simple notification class as follows:
class NamedNotification{
String title;
DateTime scheduledDate;
int id;
String description;
NamedNotification(this.scheduledDate, this.id, this.title, this.description);
}
I use this class to keep track of my notifications and add them to a list whenever a new notification is created. I do this like this:
List<NamedNotification> notifications;
onPressed: () {
setState(() {
NotificationPlugin newNotification = NotificationPlugin();
newNotification.showAtDayAndTimeNotification(_dateTime, id, title, description);
NamedNotification listNotification = NamedNotification(_dateTime, id, title, description);
print(listNotification);
notifications.add(listNotification);
id++;
});
print(id);
Navigator.pop(context);
},
However, whenever I try to add my namedNotification to the list, I get this error:
The method 'add' was called on null.
Receiver: null
Tried calling: add(Instance of 'NamedNotification')
I was wondering what the best way was to fix this.
You forgot to init notifications
Please init notifications like this
List<NamedNotification> notifications = [];
Related
I'm learning flutter by making an app following some youtube tutorials. I'm trying to make a listview of search results. I'm able to query and get data from node backend but there's this error while mapping the json to model.
The data I'm getting from api is like this:
{id: <uuid>,
userEmail: <email_string>,
profile: [{profileName: <profile_name_string>,
profileImage: <image_url_string>,
profileBio: <profile_bio_string>}]
}
With the new model class I made following an answer here I'm able to get profile model separately but when i try to get account model with all profiles I'm getting the error:type 'List<dynamic>' is not a subtype of type 'List<ProfileModel>?'. The model class is:
class AccountModel {
String userId;
String userEmail;
String? userPassword;
final List<ProfileModel>? profile;
AccountModel({
required this.userId,
required this.userEmail,
this.userPassword,
this.profile,
});
factory AccountModel.fromJson({required Map<String, dynamic> map}) {
return AccountModel(
userId: map['id'],
userEmail: map['userEmail'],
userPassword: map['userPassword'],
profile: map['profile']
.map((profileJson) => ProfileModel.fromJson(profileJson))
.toList(),
);
}
}
class ProfileModel {
String profileName;
String profileImage;
String? profileBio;
ProfileModel({
required this.profileName,
required this.profileImage,
this.profileBio,
});
factory ProfileModel.fromJson(profileJson, {Map<String, dynamic>? map}) {
if (map != null) {
return ProfileModel(
profileName: map['profileName'],
profileImage: map['profileImage'] ?? "default",
profileBio: map['profileBio'],
);
} else {
return ProfileModel(
profileName: profileJson['profileName'],
profileImage: profileJson['profileImage'] ?? "default",
profileBio: profileJson['profileBio'],
);
}
}
}
How to make the list work?
You can use List.from() in this case.
profile: map['profile'] != null
? List<ProfileModel>.from(
map['profile']?.map((p) => ProfileModel.fromJson(p)))
: null)
We are using fromMap here on ProfileModel, you can simplify just separation while both are same on ProfileModel.
More about List and List.from.
When you declared the list here as
final List<ProfileModel>? profile;
It expects the list to have only ProfileModels as ListItem even though with "?". The way to solve it is either declared a list without generic ProfileModel :
final List? profile;
Or to typecast the item you're pushing as ProfileModel.
2. profile: map['profile'] .map((profileJson) => ProfileModel.fromJson(profileJson) as ProfileModel) .toList(),
I don't know the output structures and such so try to experiment with typecasting if the above code doesn't work. May be typecasting after toList() method as List can work too.
I have a list of items i want if i clicked on any of them his bool favorite equal true using shared pref..
in more details I Have a list of objects with a bool favorite attribute. I Want to store this boolean value to shared pref..
Model Class:
class ZekrModel {
final String zekrTitle;
final String zekrImage;
final String zekrCat;
final Widget screenWidget;
bool isFav;
bool toggleDone() {
isFav = !isFav;
}
}
Provider Class:
class ZekrProvider with ChangeNotifier{
List<ZekrModel> _zekrList = [
ZekrModel(
zekrTitle: 'أذكار المساء',
zekrImage: 'assets/images/sunset.png',
zekrCat: 'Azkar',
screenWidget: AlmasaaScreen(),
),
ZekrModel(
zekrTitle: 'أذكار الصباح',
zekrImage: 'assets/images/sunrise.png',
zekrCat: 'Azkar',
screenWidget: AlsabahScreen(),
)
];
void updateFav(ZekrModel zekrModel) {
zekrModel.toggleDone();
notifyListeners();
}
List<ZekrModel> get favZekr {
return _zekrList.where((element) => element.isFav).toList();
}
}
Usage in UI:
onTap: (){
value.updateFav(zekrIndex);
},
Import the package:
import 'package:shared_preferences/shared_preferences.dart';
Your widget:
class _LoginState extends State<Login> {
Future<SharedPreferences> _prefs = SharedPreferences.getInstance();
Then, just call like that inside any method to set a bool:
final SharedPreferences prefs = await _prefs;
prefs.setBool('logado', true);
prefs.setString('logado_email', people.email);
If you want to retrieve it later:
bool status = prefs.getBool('logado') ?? false;
Issue:
As mentioned in Title, StateHasChanged does not re-render the page
Objective:
I want to Refresh the page when a button is clicked
Current Code
<button #onclick="CreatePlayer">Create User</button>
#functions {
string username;
[CascadingParameter]
Task<AuthenticationState> authenticationStateTask { get; set; }
async Task CreatePlayer()
{
var authState = await authenticationStateTask;
var user = authState.User;
var player = await PlayerData.GetByEmail(user.Identity.Name);
if (player == null)
{
player = new Player()
{
Email = user.Identity.Name,
UserName = username
};
await PlayerData.Create(player);
}
await Task.Delay(50);
StateHasChanged();
}
}
Just for the record, I add my comment in an answer :
StateHasChanged just inform the component that something changes in is state, that doesn't rerender it. The component choose by itself if it has to rerender or not. You can override ShouldRender to force the component to rerender on state changed.
#code {
bool _forceRerender;
async Task CreatePlayer()
{
var authState = await authenticationStateTask;
var user = authState.User;
var player = await PlayerData.GetByEmail(user.Identity.Name);
if (player == null)
{
player = new Player()
{
Email = user.Identity.Name,
UserName = username
};
await PlayerData.Create(player);
}
_forceRerender = true;
StateHasChanged();
}
protected override bool ShouldRender()
{
if (_forceRerender)
{
_forceRerender = false;
return true;
}
return base.ShouldRender();
}
}
On the one hand, you tell the compiler that she should create an event handler for the click event, named CreatePlayer: #onclick="CreatePlayer . This attribute compiler directive, behind the scenes, creates an EventCallback<Task> handler for you, the implication of which is that you do not need to use StateHasChanged in your code at all, as this method ( StateHasChanged ) is automatically called after UI events take place.
On the other hand, you tell the compiler that the type of the button should be set to "submit". This is wrong of course... You can't have it both. Setting the type attribute to "submit", normally submit form data to the server, but In Blazor it is prevented to work that way by code in the JavaScript portion of Blazor. Do you want to submit a form data to the server ? Always recall Blazor is an SPA Application. No submit ?
Your code should be:
<button #onclick="CreatePlayer" >Create User</button>
Just for the records, ordinarily you should inject the AuthenticationStateProvider object into your components, like this:
#inject AuthenticationStateProvider AuthenticationStateProvider
and then retrieve the AuthenticationState object. This is how your code may be rewritten:
var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
var user = authState.User;
I'm trying to make dose schedule app that when the user set the alarm the app shows a page to check if the user takes a medicine or not. and the user should choose snooze or done with swiping ("done" to the left, "snooze" to the right).
I want the app gets opened automatically from the background on time.
I've already tried "nativescript-local-notification", but this one, the user must press the notification to open or enter the app and read "nativescript background service" but it seems to be the same as I've tried.
Could you tell me the way or give me some example to do?
I've solved it by myself. I put the solution that might be helped someone like me.
First you have set an alarm.
alarm.helper.js
import * as AlarmReceiver from '#/services/AlarmReceiver' // Do not remove
export const setAlarm = data => {
const ad = utils.ad
const context = ad.getApplicationContext()
const alarmManager = application.android.context.getSystemService(android.content.Context.ALARM_SERVICE)
const intent = new android.content.Intent(context, io.nerdrun.AlarmReceiver.class)
const { id, time, title, name } = data
// set up alarm
intent.putExtra('id', id)
intent.putExtra('title', title)
intent.putExtra('name', name)
intent.putExtra('time', time.toString())
const pendingIntent = android.app.PendingIntent.getBroadcast(context, id, intent, android.app.PendingIntent.FLAG_UPDATE_CURRENT)
alarmManager.setExact(alarmManager.RTC_WAKEUP, time.getTime(), pendingIntent)
console.log('registered alarm')
}
Extends AlarmReceiver on Android.
AlarmReceiver.js
export const AlarmReceiver = android.content.BroadcastReceiver.extend('io.nerdrun.AlarmReceiver', {
init: function() {
console.log('init receiver')
},
onReceive: function(context, intent) {
console.log('You got the receiver man!!')
const activityIntent = new android.content.Intent(context, com.tns.NativeScriptActivity.class)
const id = intent.getExtras().getInt('id')
const title = intent.getExtras().getString('title')
const name = intent.getExtras().getString('name')
const time = intent.getExtras().getString('time')
activityIntent.putExtra('id', id)
activityIntent.putExtra('title', title)
activityIntent.putExtra('name', name)
activityIntent.putExtra('time', time)
activityIntent.setFlags(android.content.Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(activityIntent)
}
})
register receiver to your manifest.
AndroidManifest.xml
<receiver android:name="io.nerdrun.AlarmReceiver" />
Of course, you can extend Activity on android into your project, but I haven't implemented it.
After the receiver worked it would navigate to Main Activity, you might control whatever you want in app.js below:
app.js
application.on(application.resumeEvent, args => {
if(args.android) {
console.log('resume succeed!!!')
const android = args.android
const intent = android.getIntent()
const extras = intent.getExtras()
if(extras) {
const id = extras.getInt('id')
const title = extras.getString('title')
const name = extras.getString('name')
const time = extras.getString('time')
Vue.prototype.$store = store
Vue.prototype.$navigateTo(routes.home, { clearHistory: true, props: props })
}
}
}
})
I would like to add a list from my flutter test app to my Google Firestore.
This is my method, which adds all the data:
void postToFireStore(
{String mediaUrl, String location, String description}) {
var reference = Firestore.instance.collection('insta_posts');
reference.add({
"marked_friends": [chipstuete.toString()],
"username": currentUserModel.username,
"location": location,
"likes": {},
"mediaUrl": mediaUrl,
"description": description,
"ownerId": googleSignIn.currentUser.id,
"timestamp": new DateTime.now().toString(),
}).then((DocumentReference doc) {
String docId = doc.documentID;
reference.document(docId).updateData({"postId": docId});
});
}
Everything is working fine, expect the list "marked_friends"...
The list "chipstuete" has multiple strings:
[Martin Seubert, Lena Hessler, Vivien Jones]
But my Firestore looks like that:
At the moment the whole list is stored in marked_friends[0]...
What do I need to change, that every entry of my list "chipstuete" is stored in a seperate field of my array "marked_friends" in Firestore?
Best regards!
You have to add a method in your AppProfile class that serializes it to a List.
So in your AppProfile class:
class AppProfile {
... // Whatever fields/methods you have
// Add this method
List<String> getFriendList() {
// Somehow implement it so it returns a List<String> based on your fields
return ['name1','name2','name3'];
}
}
Then you can do
"marked_friends": chipstuete.getFriendList(),
I have the solution.
Like SwiftingDuster said, I needed a new method which serializes it to a List:
List<String> toList() {
chipstuete.forEach((item) {
newtuete.add(item.toString());
});
return newtuete.toList();
}
After that I just call toList() in my postToFirestore() Method and add "marked_friends": newtuete. Thats it!