OnClick Adapter on Kotlin - debugging

My kotlin code brakes when the onclick adapterPosition. I've debug the code but I'm still not sure what is going on and why is not working.
Here is my Category Adapter:
import android.content.Context
import android.content.Intent
import android.support.v7.widget.CardView
import android.support.v7.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import com.google.android.gms.common.internal.service.Common
import com.letsbuildthatapp.kotlinmessenger.Quizz.Model.Category
import com.letsbuildthatapp.kotlinmessenger.Quizz.Model.Interface.IOnRecyclerViewItemClickListener
import com.letsbuildthatapp.kotlinmessenger.Quizz.Model.Question
import com.letsbuildthatapp.kotlinmessenger.R
class CategoryAdapter(internal var context: Context,
internal var categoryList: List<Category>):
RecyclerView.Adapter<CategoryAdapter.MyViewHolder>() {
//This is correct
override fun onCreateViewHolder(parent: ViewGroup, p1: Int): MyViewHolder {
val itemView = LayoutInflater.from(context).inflate(R.layout.layout_category_item, parent, false)
return MyViewHolder(itemView)
}
// this is correct
override fun getItemCount(): Int {
return categoryList.size
}
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.txt_category_name.text = categoryList[position].name
holder.setiOnRecyclerViewItemClickListener(object : IOnRecyclerViewItemClickListener {
override fun onClick(view: View?, position: Int) {
// this is to direct user to the question List
com.letsbuildthatapp.kotlinmessenger.Quizz.Model.Common.Common.selectedCategory = categoryList[position]
val intent = Intent(context, Question::class.java)
context.startActivity(intent)
}
})
}
inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
internal var txt_category_name: TextView
internal var card_category: CardView
internal lateinit var iOnRecyclerViewItemClickListener: IOnRecyclerViewItemClickListener
fun setiOnRecyclerViewItemClickListener(iOnRecyclerViewItemClickListener: IOnRecyclerViewItemClickListener) {
this.iOnRecyclerViewItemClickListener = iOnRecyclerViewItemClickListener
}
init {
txt_category_name = itemView.findViewById(R.id.txt_category_name) as TextView
card_category = itemView.findViewById(R.id.card_category) as CardView
itemView.setOnClickListener(this)
}
override fun onClick(view: View?) {
iOnRecyclerViewItemClickListener.onClick(view, adapterPosition)
}
}
}
Here is the IonRecyclerViewItemClickLister
interface IOnRecyclerViewItemClickListener {
fun onClick(view: View?, position:Int)
}
I've debugged the code and it appears to work well until it reaches to this part:
override fun onClick(view: View?) {
iOnRecyclerViewItemClickListener.onClick(view, adapterPosition)
}
}
}
My question is what am I doing wrong.

Implement your interface in your activity and pass it as parameter to your Adapter. After pass it your view holder.
I'll let you with an example of my project.
My interface
MainActivity - Where I implement the Interface
My adapter

I discovered where the error was
override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
holder.txt_category_name.text = categoryList[position].name
holder.setiOnRecyclerViewItemClickListener(object : IOnRecyclerViewItemClickListener {
override fun onClick(view: View?, position: Int) {
// this is to direct user to the question List
com.letsbuildthatapp.kotlinmessenger.Quizz.Model.Common.Common.selectedCategory = categoryList[position]
val intent = Intent(context, Question::class.java)
context.startActivity(intent)
}
})
}
The error was in point to an Activity that doesn't exist.

Related

How do I make a basic animation on Skiko (Kotlin MPP bindings to Skia)?

Using Skiko and Kotlin I want to make a basic animation: A 0 to 100 counter that automatically updates the text each second.
I managed to do it, but it has a problem, it is blinking each time the window repaints.
Here is the code:
import kotlinx.coroutines.*
import org.jetbrains.skija.*
import org.jetbrains.skiko.*
import javax.swing.*
public fun main() {
val window = SkiaWindow().apply {
layer.renderer = CounterRenderer()
setSize(400, 175)
isVisible = true
defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
}
GlobalScope.launch {
for (i in 0..100) {
delay(1000)
window.layer.repaint()
}
}
}
public class CounterRenderer : SkiaRenderer {
private lateinit var canvas: Canvas
private var counter = 0
override fun onInit() {
}
override fun onDispose() {
}
override fun onReshape(width: Int, height: Int) {
}
override fun onRender(canvas: Canvas, width: Int, height: Int) {
this.canvas = canvas
val typeface = Typeface.makeFromName("Roboto", FontStyle.NORMAL)
val fontSize = 30F
val font = Font(typeface, fontSize)
val paint = Paint().setColor(0XFF000000.toInt())
canvas.drawString("Counter: ${counter++}", 10F, 50F, font, paint)
}
}
I have tried to search for examples of animations with skija or skiko without success.
I would really appreciate if you could give me some examples.
After navigating the Android Compose code, especially this class:
ComposeLayer.
I finally got it to work with this code:
import kotlinx.coroutines.*
import org.jetbrains.skija.*
import org.jetbrains.skiko.*
import javax.swing.*
public fun main() {
val window = SkiaWindow().apply {
layer.renderer = CounterRenderer()
setSize(400, 175)
isVisible = true
defaultCloseOperation = WindowConstants.EXIT_ON_CLOSE
}
GlobalScope.launch(Dispatchers.Main) {
for (i in 0..100) {
delay(500)
window.layer.redrawLayer()
}
}
}
public class CounterRenderer : SkiaRenderer {
private var counter = 0
private val typeface = Typeface.makeFromName("Roboto", FontStyle.NORMAL)
private val fontSize = 30F
private val font = Font(typeface, fontSize)
private val paint = Paint().setColor(0XFF000000.toInt())
override fun onInit() {
}
override fun onDispose() {
}
override fun onReshape(width: Int, height: Int) {
}
override fun onRender(canvas: Canvas, width: Int, height: Int) {
canvas.drawString("Counter: ${counter++}", 10F, 50F, font, paint)
}
}
To run this code you need to install the specific Main Dispatcher, in this case it is by adding this to the gradle configuration:
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.9")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-swing:1.3.9")

RxSwift Delegate Binding isn't Generated?

I am trying to bind a delegate this is what was done
/** Delegate Proxy **/
func castOrThrow<T>(_ resultType: T.Type, _ object:Any) throws -> T {
guard let returnValue = object as? T else {
throw RxCocoaError.castingError(object: object, targetType: resultType)
}
return returnValue
}
#objc
public protocol TestEventGeneratorDelegate:class {
#objc optional func asyncEventResult(int:Int)
}
open class TestEventGenerator {
public var delegate: TestEventGeneratorDelegate?
func asyncCall() {
DispatchQueue.global().asyncAfter(deadline: .now() + .seconds(1)) { [weak self] in
guard let self = self else { return }
self.delegate?.asyncEventResult!(int: 0)
}
}
}
extension TestEventGenerator: HasDelegate {
public typealias Delegate = TestEventGeneratorDelegate
}
open class RxTestDelegateProxy : DelegateProxy<TestEventGenerator,TestEventGeneratorDelegate>,
DelegateProxyType,
TestEventGeneratorDelegate {
public weak private(set) var testGenerator: TestEventGenerator?
public init(testEventGenerator: ParentObject) {
self.testGenerator = testEventGenerator
super.init(parentObject: testEventGenerator, delegateProxy: RxTestDelegateProxy.self)
}
public static func registerKnownImplementations() {
self.register { RxTestDelegateProxy(testEventGenerator: $0) }
}
}
extension Reactive where Base: TestEventGenerator {
public var delegate: DelegateProxy<TestEventGenerator, TestEventGeneratorDelegate> {
return RxTestDelegateProxy.proxy(for: base)
}
public var asyncEventResult: Observable<Int> {
let source = delegate.methodInvoked(#selector(TestEventGeneratorDelegate.asyncEventResult(int:)))
.map { (a) in
return try castOrThrow(Int.self,a[0])
}
return source
}
}
/** Delegate Proxy **/
Then when I use it
let testEventGenerator = TestEventGenerator()
textEventGenerator.rx.asyncEventResult.subscribe.... // subscribe here no rx found?
testEventGenerator.asyncCall() // call and wait for the observable to return to the delegate
It doesn't compile and says there is no such rx
I have to bind it because the person who wrote the API didn't use a callback to return the value but rather a delegate.
This is example of how he wrote the code and how I want to wrap it.
Is there a way to bind a delegate that requires a kick off from asyncCall()?
so I can chain it using flatmapLatest in a promiseLike way?
Thanks let me know!
I followed these tutorial:
How to convert Delegate to Observable RxSwift?
and
https://blog.ippon.fr/2018/11/13/rxswift-how-to-make-your-favorite-delegate-based-apis-reactive/
have conform to TestEventGenerator:ReactiveCompatible and that will fix it.

How to access UIScrollview delegates from native ios in nativescript angular?

Iam working the android and ios application using nativescript angular application.i want to access the scrollview delegates of the ios,i was accessed the scrollview delegates from the native ios following code.but it was not working:
My scrollview delegate implementation class:
// import {Injectable, EventEmitter,Output} from "#angular/core";
#ObjCClass(UIScrollViewDelegate)
export class FoodScrollDelegate extends NSObject implements UIScrollViewDelegate
{
public static ObjCProtocols = [UIScrollViewDelegate];
// #Output() yvalue:EventEmitter<any>=new EventEmitter();
private _originalDelegate:UIScrollViewDelegate;
public getY:Number=0;
constructor()
{
super();
}
public static initWithOriginalDelegate(originalDelegate:UIScrollViewDelegate):FoodScrollDelegate{
console.log("Called Method");
let delegate=<FoodScrollDelegate>FoodScrollDelegate.new();
delegate._originalDelegate=originalDelegate;
return delegate;
}
}
I have setting the scrollview delegate like this:
onScrollLoaded(args)
{
var subscroll=args.object;
var uiscrollview=subscroll.ios;
let tf=<any>this.subMenuScroll;
var newweakref=new WeakRef(uiscrollview);
const newDelegate=FoodScrollDelegate.initWithOriginalDelegate(tf._delegate);
console.log("PrintDelegate",+newDelegate);
uiscrollview.delegate=newDelegate;
}
My MenuComponet class Like this:
import { Component, OnInit, AfterViewInit,ViewChild, ElementRef} from "#angular/core";
import {Page, borderTopRightRadiusProperty} from "ui/page";
import { isIOS, isAndroid } from 'tns-core-modules/platform';
import { RadListView, ListViewEventData } from "nativescript-ui-listview";
import { RestaurentMenuModel,RestaurentSubMenuModel } from "~/app/models/restaurant";
import { ObservableArray } from "tns-core-modules/data/observable-array";
import { run } from "tns-core-modules/application/application";
import { ScrollEventData, ScrollView } from "tns-core-modules/ui/scroll-view/scroll-view";
import { RouterExtensions } from "nativescript-angular/router";
import { StackLayout } from "tns-core-modules/ui/layouts/stack-layout/stack-layout";
import { Label } from "tns-core-modules/ui/label/label";
import { analyzeAndValidateNgModules } from "#angular/compiler";
import * as utils from "tns-core-modules/utils/utils";
import { setTimeout } from "tns-core-modules/timer";
import { EventData } from "data/observable";
import { FoodScrollDelegate } from "~/app/Utils/scroll_delegate";
declare var UITableViewCellSelectionStyle;
declare var UIView, NSMutableArray, NSIndexPath;
//declare var setShowsHorizontalScrollIndicator;
#Component({
selector:"restaurant_menu",
moduleId:module.id,
templateUrl:"./restaurant_menu.component.html",
styleUrls:["./restaurant_menu.component.css"],
})
export class RestaurantMenu implements OnInit
{
//public cartCount:Number=1;
#ViewChild("ScrollList") scrollList:ElementRef;
#ViewChild("categoryList") categoryList:ElementRef;
public AllMenuList:any;
public cartTotal:any=0;
public cartItem:any=0;
public isCartVisible=false;
incrementItem:any=0;
decrementItem:any=0;
categoryContainer:Label;
subMenuContainers:StackLayout;
offsetValue:any=0;
dummyStatus:any=0;
horizontalOffsetvalue:any=0;
lengthHorizontaloffsetLength:any=0;
public selectedIndex:Number=0;
public scrollEnabled:Boolean=false;
lastItemY:Number=0;
subMenuScroll:ScrollView;
foodScrollDelegate:FoodScrollDelegate;
_delegate:any;
constructor(private page:Page,public routerExtension:RouterExtensions)
{
}
ngOnInit()
{
this.subMenuScroll=this.page.getViewById("subMenuScroll");
//this.subMenuScroll.ios.delegate=FoodScrollDelegate.initWithOriginalDelegate(this._delegate);
//console.log("PrintDelegate"+this.foodScrollDelegate.scrollViewDidEndDraggingWillDecelerate);
// this.foodScrollDelegate=new FoodScrollDelegate();
// this.foodScrollDelegate.yvalue.subscribe(yvalue=>{
// console.log("TheYYValue"+yvalue);
// });
}
public scrollViewDidEndDraggingWillDecelerate?(scrollView: UIScrollView, decelerate: boolean): void {
console.log("WillScrollEnd"+" "+decelerate);
}
public scrollViewDidScroll?(scrollView: UIScrollView): void {
this.getY=scrollView.contentOffset.y;
console.log("Yposition"+this.getY);
//this.yvalue.emit(this.getY);
}
onLoaded(event)
{
const scrollview = event.object;
if (scrollview.ios) {
scrollview.ios.showsHorizontalScrollIndicator = false;
}
else
{
scrollview.android.setHorizontalScrollBarEnabled(false);
}
}
onNavBtnTap()
{
this.routerExtension.backToPreviousPage();
}
}
Inside the i was implemented the delegate methods.but it was working
ObjCClass is an alternative syntax for ObjCProtocols. You may not need to do both.
The default delegate is attached after loaded event, so your delegate may be overwritten again. You will have to extend the ScrollView and override the attachNative method.
class MyScrollView extends ScrollView {
protected attachNative() {
(<any>ScrollView.prototype).attachNative.call(this);
if (isIOS) {
(<any>this)._delegate = FoodScrollDelegate.initWithOriginalDelegate((<any>this)._delegate);
this.nativeViewProtected.delegate = (<any>this)._delegate;
}
}
}
Register this MyScrollView,
registerElement("MyScrollView", () => MyScrollView);
Now you should be able to use MyScrollView instead of ScrollView in your HTML which will override the default delegate. If you wanted to override delegate for all ScrollView used in app, you could simply override the prototype chain of ScrollView conditionally on iOS.
(<any>ScrollView.prototype).originalAttachNative = (<any>ScrollView.prototype).attachNative;
(<any>ScrollView.prototype).attachNative = function () {
this.originalAttachNative();
const newDelegate = FoodScrollDelegate.initWithOriginalDelegate(this._delegate);
this._delegate = newDelegate;
this.nativeViewProtected.delegate = newDelegate;
};
If you like to fire an event from delegate then,
scrollViewDidEndDraggingWillDecelerate(scrollView: UIScrollView, decelerate: boolean) {
const owner = (<WeakRef<ScrollView>>(<any>this._originalDelegate)._owner).get();
if (owner) {
owner.notify({
object: owner,
eventName: "dragEnd",
decelerate: decelerate
});
}
}
Now from Angular, you could listen to the event,
HTML
(dragEnd)="onDragEnd($event)"
TS
onDragEnd(event) {
console.log(event.decelerate);
}

XCode unit test

Making CoreData model with simple class Mood:
import Foundation
import CoreData
class Mood: NSManagedObject {
static let entityName = "\(Mood.self)"
class func mood(withTitle title: String) -> Mood {
let mood: Mood = NSEntityDescription.insertNewObject(forEntityName: Mood.entityName, into: CoreDataController.sharedInstance.managedObjectContext) as! Mood
mood.title = title
return mood
}
}
extension Mood {
#NSManaged var title: String
}
and writing simple unit test for that class:
import XCTest
#testable import DiaryApp
class DiaryAppTests: XCTestCase {
var mood = Mood.mood(withTitle: "Happy")
override func setUp() {
super.setUp()
}
override func tearDown() {
super.tearDown()
}
func testExample() {
XCTAssertNotNil(self.mood)
}
}
getting error: "Could not cast value of type 'DiaryApp.Mood' (0x6000000df730) to 'DiaryAppTests.Mood' (0x10e9ed8a8)."
What am I doing wrong?
Solved it by removing all files of my project from DiaryAppTests Compile Sources (at Build Phase tab in TARGETS) - after that my classes were undefined in Tests. For make them defined added string "#testable import DiaryApp" before declaration of TestCase.

Can a MPMediaEntityPersistentID be cast to a value which can be saved to NSUserDefaults.standardUserDefaults?

I am trying to save a [MPMediaEntityPersistentID] using NSUserDefaults.standardUserDefaults(); however, I cannot cast the MPMediaEntityPresitstentID to a type which can be saved.
Here is the code:
import Foundation
import AVFoundation
import MediaPlayer
class SaveFileArray
{
var songFileArray = [MPMediaEntityPersistentID]()
init() {
songFileArray = []
}
func saveFile(id: MPMediaEntityPersistentID) {
let songID = id as NSString
songFileArray.append(id)
//Instead of printing lets save the MPMediaEntityPersistentID
print(songFileArray[0])
NSUserDefaults.standardUserDefaults().setObject(songFileArray, forKey: "time")
NSUserDefaults.standardUserDefaults().synchronize()
}
func countSavedFiles() -> Int {
return songFileArray.count
}
}
Question:
Can anyone offer me a solution as to how I can save songID into NSUserDefaults?

Resources