Using #SectionedFetchRequest , the section.id changed when i reopen my app - swiftui

I build a todo app by using #SectionedFetchRequest to fetch the CoreData in IOS 15, I have two entity, one is "group" , the other is "Item", the relationship such as below:
the code is here:
// fetch request
#SectionedFetchRequest(
sectionIdentifier: \TodoListGroup.group,
sortDescriptors: [SortDescriptor(\TodoListGroup.date, order: .forward)],
animation: .default
) private var todos: SectionedFetchResults<String, TodoListGroup>
// view
ForEach(todos) { section in
Section(header:
HStack {
Text(section.id)
Spacer()
}) {
ForEach(section) { group in
ForEach(group.itemsArray) { item in
Text(item.content)
}
}
}
}
}
I can add, delete group or items ,it's no problem and the console debug show:
▿ Section
▿ results : 1 element
- 0 : <TodoListGroup: 0x600001ca9220> (entity: TodoListGroup; id: 0x944fd1b9b585c7fc <x-coredata://670F71DD-39DA-47BD-987D-7075311C04A1/TodoListGroup/p6>; data: {
date = "2021-11-05 03:20:59 +0000";
group = SwiftUI;
items = (
"0x944fd1b9b405c7ec <x-coredata://670F71DD-39DA-47BD-987D-7075311C04A1/ToDoListItem/p10>",
"0x944fd1b9b425c7ec <x-coredata://670F71DD-39DA-47BD-987D-7075311C04A1/ToDoListItem/p11>"
);
})
- id : "SwiftUI"
but when i reopen my app in Xcode, the section.id changed ,like this:
▿ Section
▿ results : 1 element
- 0 : <TodoListGroup: 0x600001a2e6c0> (entity: TodoListGroup; id: 0xb1980459e3a37372 <x-coredata://670F71DD-39DA-47BD-987D-7075311C04A1/TodoListGroup/p6>; data: {
date = "2021-11-05 03:20:59 +0000";
group = SwiftUI;
items = "<relationship fault: 0x6000039185a0 'items'>";
})
- id : "Drawing"
the id changed to another group's name, why ?

Related

How can I create a dynamic input to .chartForegroundStyleScale

In Swift Charts the signature for chartForegroundStyleScale to set the ShapeStyle for each data series is:
func chartForegroundStyleScale<DataValue, S>(_ mapping: KeyValuePairs<DataValue, S>) -> some View where DataValue : Plottable, S : ShapeStyle
The KeyValuePairs initialiser (init(dictionaryLiteral: (Key, Value)...)) only takes a variadic parameter so any attempt to initialise a foreground style from an array (in my case <String, Color>) results in the error:
Cannot pass array of type '[(String, Color)]' as variadic arguments of type '(String, Color)'
In my application the names of the chart series are set dynamically from the data so although I can generate a [String : Color] dictionary or an array of (String, Color) tuples I can't see that it's possible to pass either of these into chartForegroundStyleScale? Unless I'm missing something this seems like a odd limitation in Swift charts that the series names need to be hard coded for this modifier?
OK I've found an approach that works as long as an arbitrary limitation to the number of entries is acceptable (example below with max size of 4:
func keyValuePairs<S, T>(_ from: [(S, T)]) -> KeyValuePairs<S, T> {
switch from.count {
case 1: return [ from[0].0 : from[0].1 ]
case 2: return [ from[0].0 : from[0].1, from[1].0 : from[1].1 ]
case 3: return [ from[0].0 : from[0].1, from[1].0 : from[1].1, from[2].0 : from[2].1 ]
default: return [ from[0].0 : from[0].1, from[1].0 : from[1].1, from[2].0 : from[2].1, from[3].0 : from[3].1 ]
}
In my case I know that there won't be more than 20 mappings so this func can just be extended to accommodate that number.
Not ideal, but it works...
You could also pass an array of colors to .chartForegroundStyleScale(range:). As long as you add the colors to the array in the same order you add your graph marks it should work fine.
Not incredibly elegant either, but this approach works with an arbitrary number or entries.
struct GraphItem: Identifiable {
var id = UUID()
var label: String
var value: Double
var color: Color
}
struct ContentView: View {
let data = [
GraphItem(label: "Apples", value: 2, color: .red),
GraphItem(label: "Pears", value: 3, color: .yellow),
GraphItem(label: "Melons", value: 5, color: .green)
]
var body: some View {
Chart {
ForEach(data, id: \.label) { item in
BarMark(
x: .value("Count", item.value),
y: .value("Fruit", item.label)
)
.foregroundStyle(by: .value("Fruit", item.label))
}
}
.chartForegroundStyleScale(range: graphColors(for: data))
}
func graphColors(for input: [GraphItem]) -> [Color] {
var returnColors = [Color]()
for item in input {
returnColors.append(item.color)
}
return returnColors
}
}

how to create a list <> in flutter from Firestore?

I am new to flutter.
How can I retrieve data from Firestore and form a new profile with every child in my collection? Second question is how can I use this list in another dart file? thank you
Thank you.
final List<Profile> demoProfiles = [
Profile (
photos: [
"https://",
],
name: "abc",
),
Profile (
photos: [
"https://",
],
name: "abc",
)
];
Assuming you have a firestore strucuture like this:
Profile
photos: []
name: ""
age: ""
distance: ""
education: ""
You can fetch data and build it into your object with this code snippet:
fetchData() async{
final db = await Firestore.instance;
List<Profile> demoProfiles = []
db.collection("Profile").get().then(function(snapshot){
snapshot.forEach((document) {
demoProfiles.add(Profile(
photos: document.data.photos,
name: document.data.name,
age: document.data.age,
distance: document.data.distance,
education: document.data.education
))
})
})
}
Edit:
1) Remove the mockedup list of profiles from your profiles class, it should not be there
2) Edit your mainController to the following:
class _MainControllerState extends State<MainController> {
List<Profile> demoProfiles = [];
demoProfiles = fetchData();
Final MatchEngine match Engine = MatchEngine (
matches:demoProfiles.map((Profile profile) => Match(profile: profile)).toList();
);
fetchData() async{
final db = await Firestore.instance;
List<Profile> list = [];
db.collection("Profile").get().then(function(snapshot){
snapshot.forEach((document) {
list.add(Profile(
photos: document.data.photos,
name: document.data.name,
age: document.data.age,
distance: document.data.distance,
education: document.data.education
))
})
});
return list;
}
}

Swift Storing Appending multiple Dictionary into array

I want to store multiple dictionary into an array so that the final results looks like so
(
{
id: 12,
task : completed
},
{
id: 15,
task : error
},
{
id: 17,
task : pending
},
)
I tried with code below but it does not give me what I want Please can someone help me out. Thanks
var FinalTaskData = [[String:AnyObject]]()
for i in 0..<taskObj.count{
let dict = ["id":taskObj[i].id!,"task":taskObj[i].task!] as [String : AnyObject]
FinalTaskData.append(dict)
}
And this gives me the output of
(
{
id = 190;
},
{
task = "Task To Be Edited";
},
{
id = 191;
},
{
task = "Also To Be Edited";
}
)
Which is not what I want. Thanks

Regex in Mongodb for ISO Date field

How can I pick all the dates with time value as 00:00:00 despite the date value? Regex doesn't work for me.
{
"_id" : ObjectId("59115a92bbf6401d4455eb21"),
"name" : "sfdfsdfsf",
"create_date" : ISODate("2013-05-13T02:34:23.000Z"),
}
something like :
db.myCollection.find({"create_date": /*T00:00:00.000Z/ })
You need to first convert created date into string of time, and if time is 00:00:00:000, then include the document.
db.test.aggregate([
// Part 1: Project all fields and add timeCriteria field that contain only time(will be used to match 00:00:00:000 time)
{
$project: {
_id: 1,
name: "$name",
create_date: "$create_date",
timeCriteria: {
$dateToString: {
format: "%H:%M:%S:%L",
date: "$create_date"
}
}
}
},
// Part 2: match the time
{
$match: {
timeCriteria: {
$eq: "00:00:00:000"
}
}
},
// Part 3: re-project document, to exclude timeCriteria field.
{
$project: {
_id: 1,
name: "$name",
create_date: "$create_date"
}
}
]);
From MongoDB version >= 4.4 we can write custom filters using $function operator.
Note: Donot forget to chage the timezone to your requirement. Timezone is not mandatory.
let timeRegex = /.*T00:00:00.000Z$/i;
db.myCollection.find({
$expr: {
$function: {
body: function (createDate, timeRegex) {
return timeRegex.test(createDate);
},
args: [{ $dateToString: { date: "$create_date", timezone: "+0530" } }, timeRegex],
lang: "js"
}
}
});

How do I hide values past the x-axis in chartjs 2.0?

How do I hide values past the x-axis in chartjs 2.0? You will notice the chart juts past the -60 mark. The x-axis uses a time scale and I have the max and min values set.
Here's my chart configuration:
{
"type":"line",
"data":{
"datasets":[
{
"label":"Scatter Dataset",
"data":[
{
"x":"2016-09-16T16:36:53Z",
"y":88.46153846153845
},
...
{
"x":"2016-09-16T16:37:54Z",
"y":88.3076923076923
}
],
"pointRadius":0,
"backgroundColor":"rgba(0,0,255,0.5)",
"borderColor":"rgba(0,0,255,0.7)"
}
]
},
"options":{
"title":{
"display":true,
"text":"Water Level Over Last 60 Seconds"
},
"animation":false,
"scales":{
"xAxes":[
{
"type":"time",
"position":"bottom",
"display":true,
"time":{
"max":"2016-09-16T16:37:54Z",
"min":"2016-09-16T16:36:54.000Z",
"unit":"second",
"unitStepSize":5
},
"ticks":{
callback: function(value, index, values) {
return "-" + (60 - 5 * index);
}
}
}
],
"yAxes":[
{
"display":true,
"ticks":{
}
}
]
},
"legend":{
"display":false
}
}
}
You can achieve this using Chart.js plugins. They let you handle events occuring while creating, updating or drawing the chart.
Here, you'll need to affect before the chart is initialised :
// We first create the plugin
var cleanOutPlugin = {
// We affect the `beforeInit` event
beforeInit: function(chart) {
// Replace `ticks.min` by `time.min` if it is a time-type chart
var min = chart.config.options.scales.xAxes[0].ticks.min;
// Same here with `ticks.max`
var max = chart.config.options.scales.xAxes[0].ticks.max;
var ticks = chart.config.data.labels;
var idxMin = ticks.indexOf(min);
var idxMax = ticks.indexOf(max);
// If one of the indexes doesn't exist, it is going to bug
// So we better stop the program until it goes further
if (idxMin == -1 || idxMax == -1)
return;
var data = chart.config.data.datasets[0].data;
// We remove the data and the labels that shouldn't be on the graph
data.splice(idxMax + 1, ticks.length - idxMax);
data.splice(0, idxMin);
ticks.splice(idxMax + 1, ticks.length - idxMax);
ticks.splice(0, idxMin);
}
};
// We now register the plugin to the chart's plugin service to activate it
Chart.pluginService.register(cleanOutPlugin);
The plugin is basically a loop through the data to remove the values that shouldn't be displayed.
You can see this plugin working in a live example on jsFiddle.
For instance, the following chat with a min set to 2 and a max to 6 ...
... would give the following result :