Flutter with SQFlite error on pushing to database - sql

I convert the data from my class instance to a map then pass that map into a database which I think is set up correctly but am getting the following error:
Tried calling: insert(conflictAlgorithm: Instance of 'ConflictAlgorithm', data: _LinkedHashMap len:5, table: "sessionchunk")
Found: insert(String, Map<String, Object?>, {String? nullColumnHack, ConflictAlgorithm? conflictAlgorithm}) => Future<int>
heres my code:
globals.dart (bad file name, more of a database helper file)
library data_practice.globals;
import 'models/sessionModel.dart';
import "package:sqflite/sqflite.dart";
import "package:path/path.dart";
var database;
Future<Database> initDatabase() async {
return database = openDatabase(
// path to the database
join(await getDatabasesPath(), 'user_data.db'),
// database version
version: 1,
// on create
onCreate: (db, version) {
return db.execute(
"CREATE TABLE sessionchunk(id INTEGER PRIMARY KEY, worktime INTEGER, breaktime INTEGER, intention TEXT, progress TEXT)");
});
}
// create an instance of this to get access to the db
pushChunk(SessionChunk chunk) async {
//create instance of the mysql database, this might cause issues
//by having multiple instances??
var db = await database;
//takes table name,
await db.insert(
table: 'sessionchunk',
data: chunk.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace);
}
sessionModel.dart (this is the main model that I'm trying to store into the sessionchunk table)
import "package:path/path.dart";
import "package:sqflite/sqflite.dart";
import "package:data_practice/main.dart";
import "package:data_practice/globals.dart" as globals;
class SessionChunk {
int id = 0;
int workTime = 40;
int breakTime = 10;
String intention = "finish backend";
String progress = "done";
SessionChunk({required id, worktime, breakTime, intention, progress});
// helper method: converts chunk data into map for sqflite db
Map<String, dynamic> toMap() {
return {
"id": this.id,
"worktime": this.workTime,
"breaktime": this.breakTime,
"intention": this.intention,
"progress": this.progress,
};
}
// helper method: prints current values of refrenced session instance
#override
String toString() {
return 'SessionChunk{id: $id, workTime: $workTime, breakTime: $breakTime, intention: $intention, progress: $progress}';
}
}
then my main.dart file:
import 'package:flutter/material.dart';
import "package:path/path.dart";
import "package:sqflite/sqflite.dart";
import "./models/sessionModel.dart";
import 'globals.dart' as globals;
//TODO: left off at step 5 in on https://docs.flutter.dev/cookbook/persistence/sqlite
void main() async {
WidgetsFlutterBinding.ensureInitialized();
Database db = await globals.initDatabase();
print(db);
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'Push to database, press below',
),
TextButton(
onPressed: () {
var chunk = SessionChunk(
id: 1,
);
globals.pushChunk(chunk);
},
child: Text("push"),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: const Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
Any help with how doing this would be greatly appreciated, pretty new to all this so please explain like Im 5! Happy Friday :)

Related

MediaState stream ConnectionState stays on waiting - audio_service flutter

I'm trying to provide my audioHandler on my Player class, but something weird is happening
When I enter the screen, the StreamBuilder will go active just fine but if i pop and navigate to the screen again the stream connect will stay on 'waiting' forever, unless i play the audio. This causes some weird behaviors. What m i doing wrong?
relevant code
Player class
final audioHandlerProvider = Provider<AudioHandler>((ref) {
AudioHandler _audioHandler = ref.read(audioHandlerServiceProvider);
return _audioHandler;
});
class _PlayerClicVozzState extends State<PlayerClicVozz> {
#override
Widget build(BuildContext context) {
return Scaffold(
extendBodyBehindAppBar: true,
backgroundColor: Color(0xff131313),
appBar: AppBar(
automaticallyImplyLeading: false,
actions: [
IconButton(
icon: Icon(Icons.clear, color: Colors.white),
onPressed: () => Navigator.of(context).pop(),
),
],
backgroundColor: Colors.transparent,
elevation: 0,
),
body: Center(
child: Consumer(builder: (context, watch, child) {
final res = watch(audioHandlerProvider);
return StreamBuilder<MediaState>(
stream: _mediaStateStream(res),
builder: (context, snapshot) {
final mediaState = snapshot.data;
return SeekBar(
duration: mediaState?.mediaItem?.duration ?? Duration.zero,
position: mediaState?.position ?? Duration.zero,
onChangeEnd: (newPosition) {
res.seek(newPosition);
},
);
},
);
...
audioservice init
late AudioHandler _audioHandler;
final audioHandlerServiceProvider = Provider<AudioHandler>((ref) {
return _audioHandler;
});
Future<void> main() async {
_audioHandler = await AudioService.init(
builder: () => AudioPlayerHandler(),
config: AudioServiceConfig(
androidNotificationChannelId: 'com.mycompany.myapp.channel.audio',
androidNotificationChannelName: 'Audio playback',
androidNotificationOngoing: true,
),
);
...
My audiohandler is exatcly the same as the plugin example
import 'package:audio_service/audio_service.dart';
import 'package:just_audio/just_audio.dart';
class AudioPlayerHandler extends BaseAudioHandler with SeekHandler {
static final _item = MediaItem(
id: 'https://s3.amazonaws.com/scifri-episodes/scifri20181123-episode.mp3',
album: "Science Friday",
title: "A Salute To Head-Scratching Science",
artist: "Science Friday and WNYC Studios",
duration: const Duration(milliseconds: 5739820),
artUri: Uri.parse(
'https://media.wnyc.org/i/1400/1400/l/80/1/ScienceFriday_WNYCStudios_1400.jpg'),
);
final _player = AudioPlayer();
/// Initialise our audio handler.
AudioPlayerHandler() {
// So that our clients (the Flutter UI and the system notification) know
// what state to display, here we set up our audio handler to broadcast all
// playback state changes as they happen via playbackState...
_player.playbackEventStream.map(_transformEvent).pipe(playbackState);
// ... and also the current media item via mediaItem.
mediaItem.add(_item);
// Load the player.
_player.setAudioSource(AudioSource.uri(Uri.parse(_item.id)));
}
// In this simple example, we handle only 4 actions: play, pause, seek and
// stop. Any button press from the Flutter UI, notification, lock screen or
// headset will be routed through to these 4 methods so that you can handle
// your audio playback logic in one place.
#override
Future<void> play() => _player.play();
#override
Future<void> pause() => _player.pause();
#override
Future<void> seek(Duration position) => _player.seek(position);
#override
Future<void> stop() => _player.stop();
/// Transform a just_audio event into an audio_service state.
///
/// This method is used from the constructor. Every event received from the
/// just_audio player will be transformed into an audio_service state so that
/// it can be broadcast to audio_service clients.
PlaybackState _transformEvent(PlaybackEvent event) {
return PlaybackState(
controls: [
MediaControl.rewind,
if (_player.playing) MediaControl.pause else MediaControl.play,
MediaControl.stop,
MediaControl.fastForward,
],
systemActions: const {
MediaAction.seek,
MediaAction.seekForward,
MediaAction.seekBackward,
},
androidCompactActionIndices: const [0, 1, 3],
processingState: const {
ProcessingState.idle: AudioProcessingState.idle,
ProcessingState.loading: AudioProcessingState.loading,
ProcessingState.buffering: AudioProcessingState.buffering,
ProcessingState.ready: AudioProcessingState.ready,
ProcessingState.completed: AudioProcessingState.completed,
}[_player.processingState]!,
playing: _player.playing,
updatePosition: _player.position,
bufferedPosition: _player.bufferedPosition,
speed: _player.speed,
queueIndex: event.currentIndex,
);
}
}
MediaStateStream and QueueStateStream
Stream<MediaState> _mediaStateStream(AudioHandler audioHandler) {
return Rx.combineLatest2<MediaItem?, Duration, MediaState>(
audioHandler.mediaItem,
AudioService.position,
(mediaItem, position) => MediaState(mediaItem, position));
}
_queueStateStream(AudioHandler audioHandler) {
return Rx.combineLatest2<List<MediaItem>?, MediaItem?, QueueState>(
audioHandler.queue,
audioHandler.mediaItem,
(queue, mediaItem) => QueueState(queue, mediaItem));
}
When you subscribe to a stream, you only start receiving new events that are emitted after the moment that you subscribe, and you may have a period of waiting for that next event.
In your implementation of _mediaStateStream you are making use of AudioService.position which only emits events when the position is changing (i.e. not paused or stalled). So even though the stream may have emitted position events in the past, if you subscribe to that stream again while paused or stalled, you will be in a waiting state until the next position event arrives which is after playback resumes again.
I would suggest wrapping your stream in rxdart's BeehaviorSubject so that it retains a memory of the last event and re-emits the last event to new listeners. Also, you could seed this BehaviorSubject with the very first value to ensure there is no waiting period even for the first listener:
_mediaStateSubject = BehaviorSubject.seeded(MediaState(
handler.mediaItem.valueOrNull,
handler.playbackState.position))
..addStream(_mediaStateStream(handler));
Then you can listen to _mediaStateSubject instead of _mediaStateStream.

How to passing data API with bottom navigation bar on flutter

I have an app that routes to a homescreen after login. This class contains a bottom navigation bar with 3 routes inside. body, forum, and profile. Inside body/ mainscreen i want to display an weather widget. I get repo code for add some weather widget. This weather widget need refresh/loading for initialize to get data from API, i want to put this loading class inside my Homescreen. but my problem is the bottom navigator bar not calling/showing on mainscreen/body. I think its only calling Get API DATA on this
Navigator.pushReplacementNamed(context, "/body", arguments: {
"weatherData": WeatherData.fromJson(data),
"selectedLocation": arguments
});
not Bottom navigation bar
_layoutPage = [Body(), Forum(), Profile()];
My question is How to merge bottom navigaton bar and this calling API data,
so every routes to body is calling loading to get api data and show bottom navigation bar.
this is my Homescreen
class HomeScreen extends StatefulWidget {
HomeScreen({Key key, this.title}) : super(key: key);
final String title;
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int _selectedIndex = 0;
#override
void initState() {
Provider.of<FirebaseOperations>(context, listen: false)
.initUserData(context);
super.initState();
}
final _layoutPage = [Body(), Forum(), Profile()];
void _onTapItem(int index) {
setState(() {
_selectedIndex = index;
});
}
// Weather
String apiKey = "MY API KEY";
SimpleLocationResult arguments;
getData({lat, lon}) async {
String latitude = lat == null ? "-6.2146" : lat.toString();
String longitude = lon == null ? "106.8451" : lon.toString();
Response response = await get(
"https://api.openweathermap.org/data/2.5/weather?units=metric&lat=$latitude&lon=$longitude&appid=$apiKey");
Map data = jsonDecode(response.body);
Navigator.pushReplacementNamed(context, "/body", arguments: {
"weatherData": WeatherData.fromJson(data),
"selectedLocation": arguments
});
}
#override
Widget build(BuildContext context) {
//loading weather
arguments = ModalRoute.of(context).settings.arguments;
Future.delayed(
Duration(seconds: 1),
() => {
arguments != null
? getData(lat: arguments.latitude, lon: arguments.longitude)
: getData()
});
return Scaffold(
body: _layoutPage.elementAt(_selectedIndex),
bottomNavigationBar: BottomNavigationBar(
backgroundColor: Colors.white,
selectedItemColor: kDarkGreenColor,
unselectedItemColor: kMainColor,
selectedLabelStyle:
TextStyle(color: kMainColor, fontFamily: 'Roboto', fontSize: 14.0),
unselectedLabelStyle: TextStyle(
color: Colors.grey[600], fontFamily: 'Roboto', fontSize: 12.0),
showUnselectedLabels: true,
items: <BottomNavigationBarItem>[
BottomNavigationBarItem(icon: Icon(EvaIcons.home), label: 'Home'),
BottomNavigationBarItem(
icon: Icon(EvaIcons.messageSquare), label: 'Forum'),
BottomNavigationBarItem(
icon: Icon(EvaIcons.person), label: 'Profile'),
],
currentIndex: _selectedIndex,
onTap: _onTapItem,
),
);
}
}

How to dynamically populate AudioSource with multiple audio data from firestore in just_audio?

I have been trying to dynamically populate AudioSource.uri() with data from firestore.
I uploaded some songs into firestore database and I wanted to use the data for a just_audio playlist in my app. I have done everything possible, and I really am not sure why its not working.
I don't want to add the song urls and other data statically as shown in the plugin example.
Here are my attempts:
First I fetched the song data using a StreamBuilder and passed it as a DocumentSnapshot List to the JustAudioPlaylist() page;
List<DocumentSnapshot> _list;
_list = snapshot.data.docs;
Flexible(
child: ListView.builder(
itemCount: 1,
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => JustAudioPlaylist(
songs: [_list[index]],
),
));
},
child:
Container(child: Center(child: Text('My Playlists'))),
);
}),
)
Then, here's the JustAudioPlaylist page where I expected to retrieve and populate the AudioSource.uri().
class JustAudioPlaylist extends StatefulWidget {
final List songs;
JustAudioPlaylist({this.songs});
#override
_JustAudioPlaylistState createState() => _JustAudioPlaylistState();
}
class _JustAudioPlaylistState extends State<JustAudioPlaylist> {
AudioPlayer _player;
int _addedCount = 0;
var _playlist;
#override
void initState() {
_playlist
.addAll(widget.songs.map((song) => ConcatenatingAudioSource(children: [
AudioSource.uri(
Uri.parse(song['song']),
tag: AudioMetadata(
album: "Science Friday",
title: song['songTitle'],
artwork: song['songImage'],
),
),
])));
I am not sure why its not working, but it produces an error "addAll was called on null". Please can anyone help?
Your relevant code is:
_playlist.addAll(...);
The error means _playlist is null. That is, _playlist is an uninitialised variable and doesn't actually contain any playlist object. I can see you declare the variable so it starts off empty:
var _playlist;
But you never actually store anything into this variable, like _playlist = ...something.... So your _playlist variable starts off null and continues to remain null.
You could do this instead:
_playlist = ConcatenatingAudioSource(children: []);
// and then later...
_playlist.addAll(widget.songs.map(...etc...));
Although addAll is intended for dynamically modifying the playlist after it's already created. But in your case, you know which songs you want to play at initialisation time, so you may as well just initialise the playlist right at the beginning and you won't have to add to it later:
_playlist = ConcatenatingAudioSource(
children: widget.songs.map(...etc...)
);

Use textfield input to get a value output

I have made a simple textfield with a number keyboard.
The user is to put in a number (to make it simple I have set the number to sum=5).
If input is = sum, the text 'correct answer' will be printed on the screen. If the user input !=sum, the returned text will be 'wrong answer'.
To test if I actually got the numbers right I have a testprint, which functions correct.
My problem is how to transform this print output to text (so that it will show as text in the app).
I have been thinking about validating and form, but since I actually already get the correct answer printed, it shows I already get the values correct. Right?
I have tried a ton of things, but nothing has worked so far, so any help is appreciated. Thank you.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Textfields2',
home: MyHomeScreen(),
);
}
}
class MyHomeScreen extends StatefulWidget {
#override
_MyHomeScreenState createState() => _MyHomeScreenState();
}
class _MyHomeScreenState extends State<MyHomeScreen> {
final int sum = 5;
String output;
String enterAnswer;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextField(
textAlign: TextAlign.center,
keyboardType: TextInputType.number,
decoration: InputDecoration(hintText: '?'),
onChanged: (val) {
enterAnswer = val;
},
),
RaisedButton(
child: Text('Submit Answer'),
onPressed: () {
if (enterAnswer.isNotEmpty) {
if (enterAnswer == sum.toString()) {
print('Correct'); //INTO TEXT
} else {
print('Wrong Answer');//INTO TEXT
}
}
})
],
),
),
);
}
}
Below the RaisedButton add a Text Widget. It should look something like this:
Text(output)
, then replace the print() statement with a setState() function updating the output:
setState(() {output = 'Correct';});
To not get an error in the first place you have to initialize the output variable, so instead of only writing
String output;
write
String output = "";

Trying to make radio buttons with using Streambuilder and Bloc in Flutter. but don't work

I tried to make radiobuttons by using Streambuilder and Bloc.
so I made streamcontroler and when radiobuttons clicked,
I made streamcontrl.add(value) implemented, but Streambuilder don't listen
that stream. I tested onchanged value of radio. and
Please figure out what's wrong with it.
This is full code.
import 'package:flutter/material.dart';
import 'dart:async';
void main(){
runApp(new MaterialApp(
home: new MyApp(),
));
}
class bloc {
StreamController <int> ctrl = StreamController() ;
get blocvalue => ctrl.stream;
void setvalue (value ) {
ctrl.sink.add(value) ; }
}
class MyApp extends StatefulWidget {
#override
_State createState() => new _State();
}
class _State extends State<MyApp>{
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text('Name here'),
),
body: new Container(
padding: new EdgeInsets.all(15.0),
child: new Center(
child: new Column(
children: <Widget>[
StreamBuilder(
stream: bloc().blocvalue,
initialData: 0,
builder: (BuildContext context, AsyncSnapshot <int> snapshot)
{
List<Widget> list = new List<Widget>();
for(int i = 0; i < 3; i++){
list.add(new RadioListTile(
value: i,
groupValue: snapshot.data,
onChanged: bloc().setvalue,
activeColor: Colors.green,
controlAffinity: ListTileControlAffinity.trailing,
title: new Text('Item: ${i}'),
dense: true,
// subtitle: new Text('sub title'),
));
}
return Column(children: list,); })
],
),
),
),
);
}
}
As mentioned by pksink in the comments, you're creating a new bloc inside build by calling setting it in StreamBuilder as bloc().blocValue. What you can do here is declare it as final myBloc = bloc(); outside of the bloc and set it on your StreamBuilder as myBloc.blocValue. With this, a new instance of bloc won't be created with every rebuild of Widget build.