Drop Down with sqlite - Flutter - list

I have database sqlite data and i want to show my data in drop down with changed id of my rows in table because in future i want to create another drop down to change to value of first drop down anyone can help ?

Working with SQLite on flutter
To gather the data from a SQLite database you could use the sqflite plugin (independently if is an iOS or Android device). You have to add the dependency to your pubspec.yaml.
dependencies:
...
sqflite: any
When you want to use sqflite you have to import the library.
import 'package:sqflite/sqflite.dart';
Next, you have to open a connection to SQLite, here we create a table in case you didn't have one
Database database = await openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
await db.execute(
'CREATE TABLE Test (id INTEGER PRIMARY KEY, name TEXT, value INTEGER, num REAL)');
});
You can insert or retrieve data using database.rawQuery.
Insert:
int primaryKeyInsertedRow = await database.rawQuery('INSERT INTO Test(name, value, num) VALUES("some name", 1234, 456.789)');
Select:
List<Map> list = await database.rawQuery('SELECT * FROM Test');
Remember to close the database when you are done with it.
await database.close();
Displaying a drop down menu list
For displaying the data you retrieve first you have to create a class that extends StatefulWidget, override the createState() method, and set your own state (in this example, SettingWidgetState)
#override
_SettingsWidgetState createState() => new _SettingsWidgetState();
Second you should define a state for it, defining a class that extends State<NameOfYourWidget>. In that class you should have a list of DropdownMenuItem<String> and a string member of the current selected element.
For the sake of convenience, in this example we are going to use a static list of cities:
List _cities = [
"Cluj-Napoca",
"Bucuresti",
"Timisoara",
"Brasov",
"Constanta"
];
Next, we override initState() setting our list of DropDownMenuItem to our list and the currently selected list element. After that we should call super.initState().
Also, we need to override the build() method. The goal is to return a Container that contains a DropDownButton, and that DropDownButton has assigned the list of items (defined in the class), the selected element (also defined in the class) and a event handler for the onChanged: property (here also are inserted additional widgets with the purpose of making it look nice)
#override
Widget build(BuildContext context) {
return new Container(
color: Colors.white,
child: new Center(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text("Please choose your city: "),
new Container(
padding: new EdgeInsets.all(16.0),
),
new DropdownButton(
value: _currentCity,
items: _dropDownMenuItems,
onChanged: changedDropDownItem,
)
],
)),
);
}
Lastly we define the method that is going to be called when a new item is selected from the list (changeDropDownItem(string selectedCity) in our example).
void changedDropDownItem(String selectedCity) {
setState(() {
_currentCity = selectedCity;
});
}
}
Link where I based my answer for drop down list. You can check out too getting started with sqflite plugin

Related

How can I update/save a Property Change for Child Item from a Hierarchical List View of Items

See the following app screens:
Content View Screen:
Content View with hierarchical list children rows disclosed:
Parent Row Detail View:
Child Row Detail View:
Referencing the above views, here are the steps I do and the resulting problem I’m trying to solve:
Launch the app.
From the Functions (Content View) presented at launch, see that there is one item listed in a list view (1.0 Move Vessel)
Click the yellow (my app accent color) disclosure arrow at the right of the list item.
Two subordinate child list rows appear under the parent list item, 1.1 Move Position and 1.2 Hold Position.
When I tap the parent item (1.0 Move Vessel) in the hierarchy list, I'm successfully able to navigate to a detail view for that tapped item.
Edit the description of the 1.0 Move Vessel item (defaults to test) of the tapped item properties in the detail view using a TextEditor view.
Click yellow Save button at top left of detail view. The app navigates back to the parent Functions (Content View).
Click on the parent 1.0 Move Vessel row again.
See that description was successfully saved and now displayed from the change made in Step 5 and 6.
Repeat steps 5 through 8 again for 1.1 Move Position list row.
See that the edit/change made to the description was not saved and the default test1 description is displayed instead (not what is wanted).
Repeat steps 5 through 8 again for 1.2 Hold Position list row.
See that the edit/change made to the description was not saved and the default test2 description is displayed instead (not what is wanted).
I think I may have a problem in my save code logic and I'm trying to investigate.
Here are the swift files for the Detail View, the View Model, and the Model (I’ve not included the content view code because that code is working ok with the detail view. Again, I think the problem is in my save button and function call code for updating the view model.
NOTE: sorry that I can’t seem to figure out how to get all the code for a file contiguous in the code view. I seem to have some closing braces that don’t appear in the code view. I think you can still follow the code.
struct FunctionDetailView: View {
#State var vesselFunction: VesselFunction
#State var vesselFunctionDescription: String
#Environment(\.presentationMode) var presentationMode
#EnvironmentObject var functionViewModel : FunctionViewModel
var body: some View {
NavigationView {
Form {
Text("Enter description below")
TextEditor(text: $vesselFunctionDescription)
.frame(height: 200)
.toolbar {
Button {
//print(vesselFunction)
vesselFunction.funcDescription = vesselFunctionDescription
//print(vesselFunction)
functionViewModel.updateVesselFunction(vesselFunction: vesselFunction)
//print(vesselFunction)
presentationMode.wrappedValue.dismiss()
} label: {
Text("Save")
}
}
}
.padding()
.navigationTitle(vesselFunction.name)
.navigationBarTitleDisplayMode(.inline)
}
}
}
struct FunctionDetailView_Previews: PreviewProvider {
static var previews: some View {
FunctionDetailView(vesselFunction: VesselFunction(id: UUID(), name: "x.x Verb Noun", funcDescription: "Description", children: nil), vesselFunctionDescription: "placeholder")
.environmentObject(FunctionViewModel())
.preferredColorScheme(.dark)
}
}
FunctionViewModel.swift
#MainActor class FunctionViewModel: ObservableObject {
#Published private(set) var decomp : [VesselFunction] = [
VesselFunction(id: UUID(), name: "1.0 Move Vessel", funcDescription: "test", children: [
VesselFunction(id: UUID(), name: "1.1 Move Position", funcDescription: "test1", children: nil),
VesselFunction(id: UUID(), name: "1.2 Hold Position", funcDescription: "test2", children: nil)
])
]
func updateVesselFunction(vesselFunction: VesselFunction) {
/*
if let index = decomp.firstIndex(where: { (existingVesselFunction) -> Bool in
return existingVesselFunction.id == vesselFunction.id
}) {
//run this code
}
*/
// cleaner version of above
if let index = decomp.firstIndex(where: { $0.id == vesselFunction.id }) {
decomp[index] = vesselFunction.updateCompletion()
}
/*
else {
for item in decomp {
if item.children != nil {
if let index = item.children?.firstIndex(where: { $0.id == vesselFunction.id }) {
item.children![index] = vesselFunction.updateCompletion()
}
}
}
} */
}
}
FunctionModel.swift
struct VesselFunction: Identifiable {
let id : UUID
let name : String
var funcDescription : String
var children : [VesselFunction]?
init(id: UUID, name: String, funcDescription: String, children: [VesselFunction]?) {
self.id = id
self.name = name
self.funcDescription = funcDescription
self.children = children
}
func updateCompletion() -> VesselFunction {
return VesselFunction(id: id, name: name, funcDescription: funcDescription, children: children)
}
}
As you can see from the else and for-in loop code commented out at the bottom of the FunctionViewModel code, I was trying to see if I needed to do something like this code to access the children VesselFunction array entries of the decomp published property. With the if let index code that is not commented out, the save function works but only for the top-level decomp array VesselFunction elements, not the nested children arrays elements.
Any help would be appreciated so all decomp array elements, both parent and nested children, can be updated when the TextEditor field is changed and the Save button is pressed in the FunctionDetailView.
NOTE: I am only showing a 1 level deep nested array of children for the decomp property. I actually want to have multiple (at least 3) level of children arrays, so if you have any ideas how to make an updateVesselFunction function work for multiple children array elements, I would appreciate it.
In the main View use ForEach($model.items) { $item in so you get a write access to the model item. In the detail View change the #State to #Binding.
The issue isn't so much your code right now, as it is the architecture of the program. You really need to reorganize the app with MVVM concepts in mind. If you are not sure of them, study Apple’s SwiftUI Tutorials & Stanford’s CS193P. Without a proper architecture, you have gotten lost down a rabbit hole to the extent that I gave up trying to fix the code.
Also, given the structure of your data, I would give serious consideration to using Core Data to model it. Your VesselFunction struct contains an array of VesselFunction, and that it much better modeled as a relationship, rather than having a struct hold an array of the same struct which can hold an array of the same struct. It is a nightmare to deal with as a struct, instead of as a Core Data class.
I would also consider make your FunctionDetailView just display data, and have a separate editing view. This will keep your view separate and easier to manage.
Lastly, you have a lot of redundancy in your naming conventions. Theoretically, you could be trying to access a piece of data at functionViewModel.funcDescription (Not to mention: functionViewModel.children[index].children[subIndex].children[subSubIndex].funcDescription); this can get a bit unwieldy. The further you go down, the worse it will get.

How to handle related stores with Svelte

I have a store with a list of entities, and another Store with and object that include one of those entities.
I want changes in the first store to be reactively reflected on the second.
I'll provide a quick example with a list of items and a list of invoices
export type Invoice = {
id: string
customer: string
items: InvoiceItem[]
}
export type InvoiceItem = {
id: string
name: string
price: number
}
Whenever the name or price of an invoice item is updated I'd like all the related Invoices to also be updated.
I created this very simple example (repl available here) but in order for the $invoices store to be updated I have to issue a $invoices = $invoices whenever the $items store changes.
Another more elegant way to do it is to subscribe to the items store and from there update the invoices store, like this:
items.subscribe(_ => invoices.update(data => data))
<script>
import { writable } from 'svelte/store'
let item1 = { id: 'item-01', name: 'Item number 01', price: 100 }
let item2 = { id: 'item-02', name: 'Item number 02', price: 200 }
let item3 = { id: 'item-03', name: 'Item number 03', price: 300 }
let items = writable([item1, item2, item3])
let invoices = writable([
{ id: 'invoice-0', customer: 'customer1', items: [item1, item3] }
])
items.subscribe(_ => invoices.update(data => data)) // refresh invoices store whenever an item is changed
const updateItem1 = () => {
$items[0].price = $items[0].price + 10
// $invoices = $invoices // alternatively, manually tell invoices store that something changed every time I change and item!!!
}
</script>
<button on:click={updateItem1}>update item 1 price</button>
<hr />
<textarea rows="18">{JSON.stringify($invoices, null, 2)}</textarea>
<textarea rows="18">{JSON.stringify($items, null, 2)}</textarea>
Is this the best way to handle this kind of scenario?
Update: thanks to the great answers and comments I came out with this more complete example: see this repl
I added some functionality that I hope will serve as basis for similar common scenarios
This is how my store api ended up:
// items.js
items.subscribe // read only store
items.reset()
items.upsert(item) // updates the specified item, creates a new one if it doesn't exist
// invoices.js
invoices.subscribe // read only store
invoices.add(invocieId, customer, date) // adds a new invoice
invoices.addLine(invoiceId, itemId, quantity)
invoices.getInvoice(invoice) // get a derived store for that particular invoice
invoice.subscribe // read only store
invoice.addLine(itemId, quantity)
A few highlights
invoices now has a lines array, each with an item and a quantity
invoices is a derived store that calculate total for each line and for the whole invoice
implementes an upsert method in items
in order to update invoices whenever an item is modified I run items.subscribe(() => set(_invoices))
also created a derived store to get a specific invoice
The solution depends on whether or not you need items independently (one item can be part of multiple invoices) or if it can be part of the invoices. If they can be one big blob, I would create invoices as a store and provide methods to update specific invoices. The items store then would be derived from the invoices.
// invoices.ts
const _invoices = writable([]);
// public API of your invoices store
export const invoices = {
subscribe: _invoices.subscribe,
addItemToInvoice: (invoideId, item) => {...},
..
};
// derived items:
const items = derived(invoices, $invoices => flattenAllInvoiceItems($invoice));
However, if they need to be separate - or if it is easier to handle item updates that way -, then I would only store the IDs of the items in the invoice store and create a derived store which uses invoices+items to create the full invoices.
// items.ts
const _items = writable([]);
// public API of your items store
export const items = {
subscribe: _items.subscribe,
update: (item) => {...},
...
};
// invoices.ts
import { items } from './items';
const _invoices = writable([]);
// public API of your invoices store
export const invoices = {
// Assuming you never want the underlying _invoices state avialable publicly
subscribe: derived([_invoices, items], ([$invoices, $items]) => mergeItemsIntoInvoices($invoices, $items)),
addItemToInvoice: (invoideId, item) => {...},
..
};
In both cases you can use invoices and items in your Svelte components like you want, interact with a nice public API and the derived stores will ensure everything is synched.
You can use a derived store like this:
let pipe = derived([invoices, items], ([$invoices, $items]) => {
return $invoices;
})
So $pipe will return an updated invoice if the invoice was changed.
$pipe will be triggered bij both stores ($items and $invoice) but only produces a result if the invoice was changed. So $pipe will not produce a result when an item changes which is not part of the invoice.
Update. I expected no result of $pipe when $invoices does not change as is the case for a writeable store. But a derived store callback will always run if $invoices or $items changes.
So we have to check if $invoices changes and use set only if we have a change.
let cache = "";
let pipe = derived([invoices, items], ([$invoices, $items], set) => {
if (JSON.stringify($invoices) !== cache) {
cache = JSON.stringify($invoices);
set($invoices);
}
}, {})

How do I display name (without extension) of files from assets folders in flutter

I have some music files in my assets folder and I want to automatically display them in a list, without having to write a line for every single music in the folder.
I think something like ListView.builder might work, but I'm pretty new in all this and not quite sure how to execute this properly.
Since it's impossible to get the names of your music files from the /assets folder within a Flutter project, I think you can try these ways:
Have a json file listing all the metadata of the files (name, artist, path in /assets, etc) and work with that file (get the name, get the path of the file, etc).
Store your music online and get them through APIs
Copy all the music from your /assets into a phone's directory, then handle the files from that directory from now on (For example: Call this method to get the names of the files). Check out this answer.
If what you want to display is like the image you describe, and if the name is not important (like ringtones), then you can simply do this (assuming you name the files by numbers from 1-10):
import 'package:flutter/material.dart';
void main() {
runApp(MaterialApp(
home: SampleScreen(),
));
}
class SampleScreen extends StatefulWidget {
#override
_SampleScreenState createState() => _SampleScreenState();
}
class _SampleScreenState extends State<SampleScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: 10,
itemBuilder: (context, index) => _buildMusicItem(index)),
);
}
Widget _buildMusicItem(int index) {
return Container(
height: 40,
margin: EdgeInsets.all(5),
padding: EdgeInsets.only(left: 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
border: Border.all(color: Colors.red, width: 2)),
alignment: Alignment.centerLeft,
child: Text('Music ${index + 1}'),
);
}
}
Result:

How to configure apollo cache to uniquely identify a child elements based on their parent primary key

What is the proper way to configure apollo's cache normalization for a child array fields that do not have an ID of their own but are unique in the structure of their parent?
Let's say we have the following schema:
type Query {
clients: [Client!]!
}
type Client {
clientId: ID
name: String!
events: [Events!]!
}
type Events {
month: String!
year: Int!
day: Int!
clients: [Client!]!
}
At first I thought I can use multiple keyFields to achieve a unique identifier like this:
const createCache = () => new InMemoryCache({
typePolicies: {
Event: {
keyFields: ['year', 'month', 'name'],
},
},
});
There would never be more than 1 event per day so it's safe to say that the event is unique for a client based on date
But the created cache entries lack a clientId (in the cache key) so 2 events that are on the same date but for different clients cannot be distinguished
Is there a proper way to configure typePolicies for this relationship?
For example the key field can be set to use a subfield:
const cache = new InMemoryCache({
typePolicies: {
Book: {
keyFields: ["title", "author", ["name"]],
},
},
});
The Book type above uses a subfield as part of its primary key. The ["name"] item indicates that the name field of the previous field in the array (author) is part of the primary key. The Book's author field must be an object that includes a name field for this to be valid.
In my case I'd like to use a parent field as part of the primary key
If you can't add a unique event id, then the fallback is to disable normalization:
Objects that are not normalized are instead embedded within their parent object in the cache. You can't access these objects directly, but you can access them via their parent.
To do this you set keyFields to false:
const createCache = () => new InMemoryCache({
typePolicies: {
Event: {
keyFields: false
},
},
});
Essentially each Event object will be stored in the cache under its parent Client object.

How do I refetch a query outside of its wrapped component?

I have two screens:
Screen1: Results
Screen2: Edit Filters
When I edit the filters on Screen2 and press back, I would like to refetch the query on Screen1 (with the newly built filter string variable). Editing the filters doesn't use a mutation or fire any Redux actions (I'm storing the users search filters/preferences in localStorage/AsyncStorage instead of a database, so no mutation). I'm merely changing the local state of the form and use that to build a filter string that I want to pass to a certain query on Screen1. I have access to the filter string on both screens if that helps.
It seems like refetch() is limited to the component its query wraps http://dev.apollodata.com/react/receiving-updates.html#Refetch so how would I re-run the query from a different screen?
I tried putting the same query on both Screen1 and Screen2, then calling the refetch on Screen2, and although the query works and gets the new data on Screen2, the same name query doesn't update on Screen1 where I actually need it. Isn't it supposed to if they have the same name? (but the filters variable changed)
If I am just designing this incorrectly and there is an easier way to do it, please let me know. I expect that if I have 2 screens, put the same query on both of them, and refetch one of the queries with a new filters variable, then the refetch should happen in both places, but it's currently treating them individually.
I did the same thing here. The scenario:
- I choose a peer to filter some messages.
- I keep the peerId into redux
- I make both components (the filter and the list) dependent on that redux value.
Like this:
1 - To put that filter value on redux (and to grab it back):
import { compose, graphql } from 'react-apollo'
import { connect } from 'react-redux';
...
export default compose(
connect(
(state,ownProps) => ({
selectedMessages: state.messages.selectedMessages,
peerId: state.messages.peerId
}),
(dispatch) => ({
clearSelection: () => dispatch(clearSelection()),
setPeer: (peerId) => dispatch(setPeer(peerId))
})
),
graphql(
PEERS_QUERY,
...
when you call connect first (using compose), before you call a graphql wrapper, or outside that wrapper, you will have peerId available as a prop on your graphql wrapper, so you can use it to filter your query:
export default compose(
connect(
(state,ownProps) => {
return {
peerId: state.messages.peerId,
selectedMessages: state.messages.selectedMessages
}
},
(dispatch) => ({
toggleMessage(messageId) {
dispatch(toggleMessage(messageId));
}
})
),
graphql( // peerId is available here because this is wrapped by connect
MESSAGES_QUERY,
{
options: ({peerId}) => ({variables:{peerId:peerId}}),
skip: (ownProps) => ownProps.peerId === '',
props: ({
...
...
...
)(MessageList);