How to bind FloatRatingView rating to variable using RxSwift - rx-swift

I am attempting to integrate this library with my RxSwift project, https://github.com/glenyi/FloatRatingView
I am unable to get the updated rating.
Here is how I have created the FloatRatingView in the Controller,
let starRater : FloatRatingView = {
let floatRatingView = FloatRatingView()
floatRatingView.emptyImage = UIImage(named: "EmptyStar")
return floatRatingView
}()
The Model contains the following,
let my_rating = Variable<Float?>(nil)
What I want to be able to do is to update the value in the my_rating variable when a user changes the rating by tapping on a star. Here is what I've written for this,
_ = starRater.rx.rating
.asObservable()
.bindTo(viewModel.my_rating.rx_value)
But here is the error I'm receiving.
Value of type 'Reactive FloatRatingView' has no member 'rating'
Here is how I will retrieve the value from my_rating variable,
let stars = self.my_rating.value
Kindly help me out. Thanks.

You need to add a bindable sink for the property, it would be something like this:
extension Reactive where Base: FloatRatingView {
/// Bindable sink for `rating` property
public var progress: UIBindingObserver<Base, Float> {
return UIBindingObserver(UIElement: self.base) { floatRatingView, rating in
floatRatingView.rating = rating
}
}
}

Related

How to update lazyColumn's item using the Flow list from room?

As below code showed, I got the list(type: Flow<List<T>>),
how can I use it to update lazyColumn's item, so when the room data changed, lazyColumn updates items accordingly?
Many thanks.
#Composable
fun SomeContent(context: Context) {
// get the view model ref
val viewModel: SomeViewModel =
viewModel(factory = SomeViewModelFactory(Db.getInstance(context)))
// get the list from room, it is a Flow list
val list = viewModel.sumDao.getAllRows()
LazyColumn(
) {
// I need to use the list in below, but got errors, how to do?
items(list.size) {
SomeListItem(list[it])
}
}
}
You must collect your FlowList as follows
val list = viewModel.sumDao.getAllRows().collectAsState(initial = emptyList())
Instead of items, use itemsIndexed
itemsIndexed(list) {idx, row -> SomeListItem(row)}
Let me know if the above works.
if using vn1gam's solution, might need to do
itemsIndexed(list.value) {idx, row -> SomeListItem(row)}

How to write data back to storage?

I have a method called changePlaceName and i know it is working but after i call getPlaces to see the changes, i don't see the new place name instead i see the name when i created a new place.
this is changePlaceName
export function changePlaceName(placeId: u32, placeName: PlaceName): void {
assert(placeId >= 0, 'Place ID must be >= 0');
const place = Place.find(placeId);
logging.log(place.name); //gives "Galata Tower"
place.name = placeName;
logging.log(place.name); // gives "New Galata Tower"
}
I need to save it somehow but I don't know how to do it.
I also tried this way;
export function changePlaceName(placeId: u32, placeName: string): void {
assert(placeId >= 0, 'Place ID must be >= 0');
const place = Place.find(placeId);
logging.log(place.name);
place.name = placeName;
let newPlace = storage.get<string>(placeName, 'new galata tower');
storage.set<string>(placeName, newPlace);
logging.log('New place is now: ' + newPlace);
}
Now my visual code is complaining about the newPlace inside the storage.set
How do I fix it?
What is the code of Place.find? I assume you are using a persistent map under the hood.
Is there a Place.set? You need to store the Place back to the same key used to find it.
because you're using some kind of class to manage the concept of "Place", why not add an instance method to that class to save() the place once you've changed it's name?
would help if you also posted your code for Place here, by the way
my guess is that it looks something like this?
!note: this is untested code
#nearBindgen
class Place {
private id: number | null
private name: string
static find (placeId: number): Place {
// todo: add some validation for placeId here
const place = places[placeId]
place.id = placeId
return place
}
// here is the instance method that can save this class
save(): bool {
places[this.id] = this
}
}
// a collection of places where placeId is the index
const places = new PersistentVector<Place>("p")

Can I grade assignments "logged as student" with Google Classroom API?

I have an app using Google Classroom API. When connected as the teacher I can create course works and assignments. When connected as a student I can list my assignments and I can turn in a specific assignment.
I am using the REST API:
https://developers.google.com/classroom/reference/rest
When (logged as student) I turn in an assignment but I would like to include a draft grade.
I know if I were logged as the teacher I could set the grade, but what I want is the app calculating the draft grade based on some specific built-in logic, so that the teacher does not have to do it on their own for each student.
According to the documentation, both "draftGrade" and "assignedGrade" can only be updated by the teacher.
https://developers.google.com/classroom/reference/rest/v1/courses.courseWork.studentSubmissions#StudentSubmission
Any ideas about how to automate setting grades for submissions?
I think that is not possible: you cannot update the draftGrade with student privileges.
What you can do:
From the "student" session you save a draft grade in the application DB, associated to the Submission ID.
From the "teacher" session, and hence "teacher" permissions, you get the grade from the application DB and I call the Path query to set the draftGrade.
Some code (Swift, using GoogleAPIClientForREST) for step 2:
func executeQuery_GradeSubmission(studentSubmission: GTLRClassroom_StudentSubmission) -> GTLRServiceTicket? {
guard let courseID = self.myClassroom?.courseID,
let courseWorkID = self.selectedCourseWorkID else { return nil }
if let grade = self.gradesForSelectedWorkID?[studentSubmission.identifier!] {
studentSubmission.draftGrade = NSNumber(floatLiteral: Double(grade))
}
let query = GTLRClassroomQuery_CoursesCourseWorkStudentSubmissionsPatch.query(withObject: studentSubmission,
courseId: courseID,
courseWorkId: courseWorkID,
identifier: studentSubmission.identifier!)
query.updateMask = "draftGrade"
return self.myClassroom?.service.executeQuery(query,
delegate: self,
didFinish: #selector(displayGradeSubmissionResult(ticket:finishedWithObject:error:)))
}
#objc func displayGradeSubmissionResult(ticket: GTLRServiceTicket, finishedWithObject: GTLRObject, error: Any?){
let classroomSubmissionResponse = finishedWithObject as? GTLRClassroom_StudentSubmission
if let classroomError = error as? NSError {
print("displayGradeSubmissionResult. ERROR: \(classroomError.description)")
// TODO: inform something went wrong
} else {
if let submissionItems = self.classroomSubmissionsResponse?.studentSubmissions {
for submissionItem in submissionItems {
if submissionItem.identifier == classroomSubmissionResponse?.identifier {
submissionItem.draftGrade = classroomSubmissionResponse?.draftGrade
}
}
}
}
}

Opening and using a database from another view controller

I have created a database in one view controller and I would like to open it and access it in another view controller. I was wondering how to open up a existing database from one view controller in another view controller. I intend to open up the database and be able to update a row, so I would also need access to the "parts" (ex. id, name, email). Could you help me? Anything would be helpful. Thanks!
You can access your DB from any VC. Code (which you will probably use anywhere you want to access your DB from) would be like
let path = NSSearchPathForDirectoriesInDomains(
.documentDirectory, .userDomainMask, true
).first!
do {
let db = try Connection("\(path)/<your.db.filename>")
let recordsTable = Table("records")
//or whatever you'd like to do, extract, modify, insert or delete
}
catch let error {
print("Data operation failed for records table: \(error)")
}
Instead of copying same code all over your project, you can separately create your own class for any of your DB operations and access it from anywhere:
class DatabaseOps {
//..
func getHighscoreTable() -> Array<HighScoreDataArray> {
let path = NSSearchPathForDirectoriesInDomains(
.documentDirectory, .userDomainMask, true
).first!
var highscores = [HighScoreDataArray]()
do {
let db = try Connection("\(path)/tasksolver.db")
let score = Expression<Int>("Score")
let username = Expression<String>("Username")
let recordsTable = Table("records").order(score.desc).limit(10)
for row in try db.prepare(recordsTable) {
let highscore = HighScoreDataArray(score: Int(row[score]), username: String(row[username]))
highscores += [highscore]
}
} catch let error {
print("Data operation failed for records table: \(error)")
}
return highscores
}
//..
}
class RecordsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
var myDb : DatabaseOps = DatabaseOps()
//...
super.viewDidLoad()
//get the data from database by using myDB method
myHighScoreTable = myDb.getHighscoreTable()
Also, before you try it in different VCs - don't forget to make sure you have your DB file in place. If it is not, let db = try Connection will create an empty database for you, which will not contain any of your data or tables you want to access.

Web API parameter filtering

This must be simple and I'm being incredibly dense but I can't find an example to help me figure it out. I want to filter my list of tblAsset items by their assessmentId which is passed in through a parameter. I'm able to get the parameter value ok, but I'm not sure how to write the query.
My model is built from an existing Database using the Model creation wizard.
Thanks for any help!
public IEnumerable<tblAsset> GettblAssets()
{
NameValueCollection nvc = HttpUtility.ParseQueryString(Request.RequestUri.Query);
var assessmentId = nvc["aid"];
//limit the assets by assessmentId somehow and return
}
You could use the .Where extension method on the IQueryable<tblAsset> instance returned by your database:
public IEnumerable<tblAsset> GettblAssets()
{
NameValueCollection nvc = HttpUtility.ParseQueryString(Request.RequestUri.Query);
var assessmentId = nvc["aid"];
// TODO: you might need to adjust the property names of your model accordingly
// Also if the assessmentId property is an integer on your model type
// you will need to parse the value you read from the request to an integer
// using the int.Parse method
return db.tblAsset.Where(a => a.assessmentId == assessmentId);
}

Resources