How to find commit distance using JGit? - java

I've a little Kotlin utility class that uses JGit to find the following information:
branch, latestCommit, lastTag, lastTagCommit, lastReleaseTag, lastReleaseTagCommit, commitDistance
where lastReleaseTag is found by matching a given prefix.
All that is working, except for commitDistance, which is the number of commits between the latestCommit and a tag. I'm using RevWalkUtils.count, but it always returns zero.
class GitRepo(dir: File) {
private val log = LoggerFactory.getLogger(GitRepo::class.java)
constructor(dir: String) : this(File(dir))
private val repository = FileRepositoryBuilder()
.setGitDir(File(dir, ".git"))
.readEnvironment()
.findGitDir()
.setMustExist(true)
.build()
#JvmOverloads
fun info(releaseTagPrefix: String = "release/"): RepoInfo {
repository.use { repo ->
RevWalk(repo).use { walk ->
val latestCommit: RevCommit? = Git(repository).use {
try {
it.log().setMaxCount(1).call().iterator().next()
} catch (ex: NoHeadException) {
log.warn("Repository has no HEAD")
null
}
}
val tags = repo.refDatabase.getRefsByPrefix("refs/tags/")
.groupBy { it.name.startsWith("refs/tags/$releaseTagPrefix") }
.mapValues { entry ->
entry.value.maxByOrNull { it.name }
}
val lastReleaseTag = tags[true]
val lastTag = tags[false]
val lastTagCommit = lastTag?.toRevCommit(walk)
val commitDistance = if (latestCommit == null || lastTagCommit == null) 0
else RevWalkUtils.count(walk, latestCommit, lastTagCommit)
return RepoInfo(
repo.branch,
latestCommit?.toObjectId()?.shorten(),
lastTag?.tagName(),
lastTag?.objectId?.shorten(),
lastReleaseTag?.tagName(),
lastReleaseTag?.objectId?.shorten(),
commitDistance
)
}
}
}
private fun ObjectId.shorten(): String {
return name.take(8)
}
private fun Ref.tagName(): String? {
return "refs\\/tags\\/(.*)".toRegex().find(this.name)?.groupValues?.get(1)
}
private fun Ref.toRevCommit(revWalk: RevWalk): RevCommit? {
val id = repository.refDatabase.peel(this)?.peeledObjectId ?: objectId
return try {
revWalk.parseCommit(id)
} catch (ex: MissingObjectException) {
log.warn("Tag: {} points to a non-existing commit", tagName())
null
}
}
}
A command line invocation of git rev-list --count start...end returns 33.
JGit 5.9.0.202009080501-r.

Thanks to #fredrik, it's just a simple matter of swapping the commits in the call to RevWalkUtils.count. However, it turns out that RevWalkUtils.count is returning a greater number than git rev-list --count start...end, perhaps because of this:
count the number of commits that are reachable from start until a commit that is reachable from end is encountered
I ended up changing my implementation as follows:
class GitRepo(dir: File) {
constructor(dir: String) : this(File(dir))
private val log = LoggerFactory.getLogger(GitRepo::class.java)
private val repository = FileRepositoryBuilder()
.setGitDir(File(dir, ".git"))
.readEnvironment()
.findGitDir()
.setMustExist(true)
.build()
#JvmOverloads
fun info(tagPrefix: String = ".*"): RepoInfo {
repository.use { repo ->
val lastTag: Ref? = repo.refDatabase.getRefsByPrefix("refs/tags/")
.filter { it.name.matches("refs/tags/$tagPrefix".toRegex()) }
.maxByOrNull { it.name }
var latestCommit: RevCommit? = null
var lastTagCommit: RevCommit?
var commitDistance = 0
Git(repo).use { git ->
try {
latestCommit = git.log().setMaxCount(1).call().firstOrNull()
lastTagCommit = lastTag?.let {
val id = repo.refDatabase.peel(it)?.peeledObjectId ?: it.objectId
git.log().add(id).call().firstOrNull()
}
if (latestCommit != null && lastTagCommit != null) {
commitDistance = git.log().addRange(lastTagCommit, latestCommit).call().count()
}
} catch (ex: NoHeadException) {
log.warn("Repository has no HEAD")
} catch (ex: MissingObjectException) {
log.warn("Tag: {} points to a non-existing commit: ", lastTag?.tagName(), ex.objectId.shorten())
}
return RepoInfo(
repo.branch,
latestCommit?.toObjectId()?.shorten(),
lastTag?.tagName(),
lastTag?.objectId?.shorten(),
commitDistance
)
}
}
}
private fun ObjectId.shorten(): String {
return name.take(8)
}
private fun Ref.tagName(): String? {
return "refs\\/tags\\/(.*)".toRegex().find(name)?.groupValues?.get(1)
}
}

Related

Android yuv_420_888 mp4 1080p output is graysale on some devices like S21 and green bars on S22

I am trying to make an mp4 video recoding, its not working on all android devices and I am getting grayscale recordings on S21 Android OS 12, S22 Green bars
Not sure where I went wrong, Following is all the possible code that could impact
What I am expecting is that it should work on all devices producing colored 1080p mp4 video and no green bars
ImageAnalysis Initilization
val imageAnalysis = ImageAnalysis.Builder()
// enable the following line if RGBA output is needed.
// .setOutputImageFormat(ImageAnalysis.OUTPUT_IMAGE_FORMAT_RGBA_8888)
.setOutputImageRotationEnabled(true)
//.setTargetAspectRatio(quality.getAspectRatio(quality))
.setTargetResolution(fhdResolution)
.setBackpressureStrategy(ImageAnalysis.STRATEGY_BLOCK_PRODUCER)
.build()
imageAnalysis.setAnalyzer(executorService, ImageAnalysis.Analyzer { imageProxy ->
// convert image to bytearray before closing
val bytearray = ImageUtil.imageToNv21ByteArray(imageProxy)
imageProxy.close()
frameMetadata?.let {
val metadata = it
bytearray?.let {
trySend(
FrameWrapper(
it,
imageProxy.imageInfo,
imageProxy.width,
imageProxy.height,
state,
metadata
)
)
}
}
})
imageToNv21ByteArray
fun imageToNv21ByteArray(image: ImageProxy): ByteArray? {
var data: ByteArray? = null
if (image.format == ImageFormat.YUV_420_888) {
data = yuv_420_888toNv21(image) // <=== this seems to be the best one
} else {
Timber.e("Unrecognized image format: %s", image.format)
}
return data
}
yuv_420_888toNv21
private fun yuv_420_888toNv21(image: ImageProxy): ByteArray? {
val yPlane = image.planes[0]
val uPlane = image.planes[1]
val vPlane = image.planes[2]
val yBuffer = yPlane.buffer
val uBuffer = uPlane.buffer
val vBuffer = vPlane.buffer
yBuffer.rewind()
uBuffer.rewind()
vBuffer.rewind()
val ySize = yBuffer.remaining()
var position = 0
// TODO(b/115743986): Pull these bytes from a pool instead of allocating for every image.
val nv21 = ByteArray(ySize + image.width * image.height / 2)
// Add the full y buffer to the array. If rowStride > 1, some padding may be skipped.
for (row in 0 until image.height) {
yBuffer[nv21, position, image.width]
position += image.width
yBuffer.position(
Math.min(ySize, yBuffer.position() - image.width + yPlane.rowStride)
)
}
val chromaHeight = image.height / 2
val chromaWidth = image.width / 2
val vRowStride = vPlane.rowStride
val uRowStride = uPlane.rowStride
val vPixelStride = vPlane.pixelStride
val uPixelStride = uPlane.pixelStride
// Interleave the u and v frames, filling up the rest of the buffer. Use two line buffers to
// perform faster bulk gets from the byte buffers.
val vLineBuffer = ByteArray(vRowStride)
val uLineBuffer = ByteArray(uRowStride)
for (row in 0 until chromaHeight) {
vBuffer[vLineBuffer, 0, Math.min(vRowStride, vBuffer.remaining())]
uBuffer[uLineBuffer, 0, Math.min(uRowStride, uBuffer.remaining())]
var vLineBufferPosition = 0
var uLineBufferPosition = 0
for (col in 0 until chromaWidth) {
nv21[position++] = vLineBuffer[vLineBufferPosition]
nv21[position++] = uLineBuffer[uLineBufferPosition]
vLineBufferPosition += vPixelStride
uLineBufferPosition += uPixelStride
}
}
return nv21
}
Mp4EncoderFrameFlowConsumer
class Mp4EncoderFrameFlowConsumer(var context: Context, callback: (videoStartTime: Long) -> Unit) : OpsisModule {
var recording = false
var pendingStart = false
var encoder: VideoEncoder? = null
var job: Job? = null
var videoStartTime: Long? = null
var callback:((videoStartTime: Long) -> Unit) = callback
override fun start() {
thread(start = true) {
val frameFlow: FrameFlow = FlowManager.getFlow(FlowManager.FlowType.frame) as FrameFlow
runBlocking {
job = CoroutineScope(Job()).launch {
frameFlow.frameFlow().collect {
if (pendingStart) {
val wrapper = it
pendingStart = false
encoder?.let {
it.startEncoding(wrapper.width, wrapper.height)
}
}
if (recording) {
if (videoStartTime == null) {
videoStartTime = it.frameMetadata.timestamp
callback(videoStartTime!!)
}
addFrame(it)
}
}
}
}
}
Timber.d("Done encoder consumer")
}
override fun startRecording() {
recording = true;
Timber.d("Start Recording")
encoder = VideoEncoder()
pendingStart = true
}
override fun stopRecording(startFrame:Long, dir:File, callback: (result: File) -> Unit) {
if (recording) {
recording = false
encoder?.let {
try {
it.stopEncoding() { file ->
// copy file to directory
val newfile = File(dir.absolutePath + "/breeze_video.mp4")
if (file.exists()) {
file.copyTo(newfile)
file.delete()
}
callback(newfile)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
override fun stop() {
Timber.d("STOPPING ENCODER CONSUMER")
job?.let {
it.cancel()
}
}
suspend fun addFrame(wrapper: FrameWrapper) {
// Timber.d("RECORD META ${wrapper.frameMetadata.timestamp} FRAME ${wrapper.info.timestamp}")
encoder?.let {
it.addFrame(wrapper.image)
}
}
}
VideoEncoder
class VideoEncoder() {
var mOutputFile: File? = null
private var mediaCodec: MediaCodec? = null
private var mediaMuxer: MediaMuxer? = null
private var mGenerateIndex = 0
private var mTrackIndex = 0
private var mNoMoreFrames = false
private var mAbort = false
private val _encodingFlow = MutableSharedFlow<ByteArray>(
extraBufferCapacity = 20,
onBufferOverflow = BufferOverflow.DROP_OLDEST
)
init {
mOutputFile = File(Util.getFilePath("opsis_video", ".mp4"))
thread(start = true) {
runBlocking {
CoroutineScope(Job()).launch {
_encodingFlow.collect {
mediaCodec?.let { codec ->
mediaMuxer?.let { muxer ->
try {
val TIMEOUT_USEC: Long = 500000
val inputBufIndex = codec.dequeueInputBuffer(TIMEOUT_USEC)
val ptsUsec =
computePresentationTime(mGenerateIndex.toLong(), FRAME_RATE)
if (inputBufIndex >= 0) {
val inputBuffer: ByteBuffer? =
codec.getInputBuffer(inputBufIndex)
inputBuffer?.let { buffer ->
buffer.clear()
buffer.put(it)
try {
codec.queueInputBuffer(inputBufIndex, 0, it.size, ptsUsec, 0)
} catch (e: Exception) {
e.printStackTrace()
}
mGenerateIndex++
}
}
val mBufferInfo = MediaCodec.BufferInfo()
val encoderStatus =
codec.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC)
if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
// no output available yet
Timber.e("No output from encoder available")
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
// not expected for an encoder
val newFormat = codec.outputFormat
mTrackIndex = muxer.addTrack(newFormat)
muxer.start()
} else if (encoderStatus < 0) {
Timber.e("unexpected result from encoder.dequeueOutputBuffer: $encoderStatus")
} else if (mBufferInfo.size != 0) {
val encodedData: ByteBuffer? =
codec.getOutputBuffer(encoderStatus)
if (encodedData == null) {
Timber.e("encoderOutputBuffer $encoderStatus was null")
} else {
encodedData.position(mBufferInfo.offset)
encodedData.limit(mBufferInfo.offset + mBufferInfo.size)
muxer.writeSampleData(
mTrackIndex,
encodedData,
mBufferInfo
)
codec.releaseOutputBuffer(encoderStatus, false)
}
}
} catch (e: Exception) {
e.printStackTrace()
}
}
}
}
}
}
}
}
fun encodingFlow(): Flow<ByteArray> {
return _encodingFlow
}
val isEncodingStarted: Boolean
get() = mediaCodec != null && mediaMuxer != null && !mNoMoreFrames && !mAbort
fun startEncoding(width: Int, height: Int) {
mWidth = width
mHeight = height
val outputFile = mOutputFile!!
val outputFileString: String
outputFileString = try {
outputFile.getCanonicalPath()
} catch (e: IOException) {
Timber.e("Unable to get path for $outputFile")
return
}
val codecInfo = selectCodec(MIME_TYPE)
if (codecInfo == null) {
Timber.e("Unable to find an appropriate codec for " + MIME_TYPE)
return
}
Timber.d("found codec: " + codecInfo.name)
mediaCodec = try {
MediaCodec.createByCodecName(codecInfo.name)
} catch (e: IOException) {
Timber.e("Unable to create MediaCodec " + e.message)
return
}
val mediaFormat = MediaFormat.createVideoFormat(MIME_TYPE, mWidth, mHeight)
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE)
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE)
mediaFormat.setInteger(
MediaFormat.KEY_COLOR_FORMAT,
CodecCapabilities.COLOR_FormatYUV420Flexible
)
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, I_FRAME_INTERVAL)
mediaCodec?.let { codec ->
codec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
codec.start()
mediaMuxer = try {
MediaMuxer(outputFileString, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
} catch (e: IOException) {
Timber.e("MediaMuxer creation failed. " + e.message)
return
}
Timber.d("Initialization complete. Starting encoder...")
}
}
suspend fun addFrame(frame: ByteArray) {
_encodingFlow.emit(frame)
}
fun stopEncoding(callback: (result: File) -> Unit) {
release()
callback(mOutputFile!!)
}
private fun release() {
mediaCodec?.let {
try {
it.stop()
it.release()
} catch (e: Exception) {
e.printStackTrace()
}
mediaCodec = null
}
mediaMuxer?.let {
try {
it.stop()
it.release()
} catch (e: Exception) {
e.printStackTrace()
}
mediaMuxer = null
}
}
// from google:
// https://android.googlesource.com/platform/cts/+/jb-mr2-release/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java#1128
private fun computePresentationTime(frameIndex: Long, framerate: Int): Long {
return 132 + frameIndex * 1000000 / framerate
}
companion object {
private const val MIME_TYPE = "video/avc" // H.264 Advanced Video Coding
private var mWidth = 0
private var mHeight = 0
private const val BIT_RATE = 16000000
private const val FRAME_RATE = 30 // Frames per second
private const val I_FRAME_INTERVAL = 1
private fun selectCodec(mimeType: String): MediaCodecInfo? {
val numCodecs = MediaCodecList.getCodecCount()
for (i in 0 until numCodecs) {
val codecInfo = MediaCodecList.getCodecInfoAt(i)
if (!codecInfo.isEncoder) {
continue
}
val types = codecInfo.supportedTypes
for (j in types.indices) {
if (types[j].equals(mimeType, ignoreCase = true)) {
return codecInfo
}
}
}
return null
}
}
}

Why my `Selector` always return same `SelectionKey` in java NIO?

My NetSelector class:
class NetSelector(
private var selector: Selector,
private val emptySelectThreshold: Int
) : NetSelector {
private var keyIterator: MutableIterator<SelectionKey> = emptyKeyIterator
private var lastEmptySelectTime: Long = 0L
private var emptySelectCount: Int = 0
private var isClose = false
override fun next(): SelectionKey {
if (keyIterator.hasNext()) {
val next = keyIterator.next()
keyIterator.remove()
println("next>>>>>>>> $next")
return next
}
var selectCount = selector.select()
println("selectCount>>>>>>>>> $selectCount")
while (selectCount == 0) {
val now = epochMillis()
if (now == lastEmptySelectTime) {
emptySelectCount++
if (emptySelectCount >= emptySelectThreshold) {
//High CPU if select count is always 0
emptySelectCount = 0
rebuildSelector()
return next()
} else {
selectCount = selector.select()
}
} else {
lastEmptySelectTime = now
emptySelectCount = 0
selectCount = selector.select()
}
}
val selectedKeys = selector.selectedKeys()
keyIterator = selectedKeys.iterator()
return next()
}
private fun rebuildSelector() {
val newSelector = Selector.open()
for (key in selector.keys()) {
if (!key.isValid || key.interestOps() == 0) {
continue
}
key.cancel()
val channel = key.channel()
val attachment = key.attachment()
channel.register(newSelector, key.interestOps(), attachment)
selector.selectNow()
}
synchronized(this) {
selector.close()
selector = newSelector
if (isClose) {
newSelector.close()
}
}
}
override fun close() {
synchronized(this) {
selector.close()
isClose = true
}
}
companion object {
private val emptyKeyIterator: MutableIterator<SelectionKey> = object : MutableIterator<SelectionKey> {
override fun hasNext(): Boolean = false
override fun next(): SelectionKey = throw NoSuchElementException("This iterator is empty!")
override fun remove() = throw IllegalStateException("This iterator is empty!")
}
}
}
It returns same SelectionKey when I use next() method:
selectCount>>>>>>>>> 1
next>>>>>>>> sun.nio.ch.SelectionKeyImpl#30beb8f5
selectCount>>>>>>>>> 1
next>>>>>>>> sun.nio.ch.SelectionKeyImpl#30beb8f5
Where is the mistake?

How to fix API authentication problem in Kotlin Android app?

I developed an API in Laravel for reading some data with authentication. Now in my app I need to send the token in my header for API to respond. Every time i login with app, I'm getting token without problem, but i can't provide token in header and it's returning a null token response. Now every time i reopen my app everything is fine but problem appear only when i login.
Please read my code and say if you found the bug.
This is my (AppServer.kt). I use this for adding the token to my header
class AppServer private constructor(private val client: INetworkClient) : IAppServer {
private val gson = Gson()
companion object {
private var instance: AppServer? = null
fun getInstance(): AppServer {
val token = AppLoggedInUser.getInstance()?.userProfile?.userToken ?: ""
if (instance == null)
instance = AppServer(
MixedNetworkClient(
mHeaders = mutableMapOf(
Headers.CONTENT_TYPE to "application/json",
"X-Requested-With" to "XMLHttpRequest",
"Authorization" to "Bearer $token"
),
mBasePath = "https://myWebsiteURL.com/"
)
)
return instance!!
}
}
override fun getPurchasedItems(): Observable<Pair<ResponseState, List<OrderInfo>?>> {
return Observable.create<Pair<ResponseState, List<OrderInfo>?>> { emitter ->
val (items, statusCode, msg, error) =
client.get(
"api/users/${AppLoggedInUser.getInstance().userProfile.userId}/orders",
{ responseStr ->
try {
val orders = mutableListOf<OrderInfo>()
val jArray = JSONArray(responseStr)
for (i in 0 until jArray.length()) {
val jObject = jArray.getJSONObject(i)
val order =
gson.fromJson<OrderInfo>(jObject.toString(), OrderInfo::class.java)
if (order.isPaymentSuccessful)
orders.add(order)
}
if (orders.isEmpty())
emitter.onNext(pair(empty(), null))
else
emitter.onNext(pair(success(), orders))
} catch (t: Throwable) {
Timber.e(t)
emitter.onNext(pair(ResponseState.internalError(t), null))
}
})
}.attachSchedulers()
}
override fun getDiscountDetailsById(id: Int): Observable<Pair<ResponseState, DiscountDetails?>> {
return Observable.create<Pair<ResponseState, DiscountDetails?>> { emitter ->
try {
client.post("api/post", listOf("post_id" to id.toString())) { responseStr ->
val jObject = JSONObject(responseStr)
var discount: DiscountDetails? = null
if (jObject.has("ID"))
discount =
gson.fromJson<DiscountDetails>(jObject.toString(), DiscountDetails::class.java)
if (discount != null)
emitter.onNext(pair(success(), discount))
else
emitter.onNext(pair(notFound404(), null))
}
} catch (t: Throwable) {
Timber.e(t)
emitter.onNext(pair(ResponseState.internalError(t), null))
}
}.attachSchedulers()
}
}
and this is my (AppLoggedInUser.java) I use it for getting my current user token.
package com.fartaak.gilantakhfif.utilities;
import android.content.Context;
import com.fartaak.gilantakhfif.backend.server.ParsingGSON;
import com.fartaak.gilantakhfif.model.UserProfile;
public class AppLoggedInUser extends AppPreferences {
public static final String NAM_LOGIN_SdPs = "login";
public static final String KEY_USER_TOKEN = "tokenPor";
private static AppLoggedInUser mInstance;
private final String KEY_LOGIN = "prefP";
private boolean isCompletelyRegistered;
public static void init(Context context) {
if (mInstance == null) {
mInstance = new AppLoggedInUser(context);
}
}
public static AppLoggedInUser getInstance() {
if (mInstance != null) {
return mInstance;
} else {
throw new IllegalStateException(
"you should call init to initialize only once per app launch before calling getInstance");
}
}
private AppLoggedInUser(Context context) {
super(NAM_LOGIN_SdPs, context);
}
public String getUserToken() {
return getField(KEY_USER_TOKEN);
}
public void clearUserProfile() {
removeField(KEY_LOGIN);
}
public UserProfile getUserProfile() {
String data = getField(KEY_LOGIN);
if (data == null) {
return null;
}
//return new Gson().fromJson(data, UserProfile.class);
return ParsingGSON.getInstance().getParsingJSONObject(data, UserProfile.class, null);
}
public boolean isRegisterCompleted() {
if (!isCompletelyRegistered) {
UserProfile userProfile = getUserProfile();
if (userProfile.getUserName() == null) {
return false;
} else {
isCompletelyRegistered = true;
}
}
return true;
}
public boolean isUserProfile() {
return isField(KEY_LOGIN);
}
public void setUserProfile(UserProfile userProfile) {
String json = ParsingGSON.getInstance().toJSONObject(userProfile, UserProfile.class, null);
setField(KEY_LOGIN, json);
}
}
I think the problem is with my second class.

JavaFX TreeTableView unable to update cell values

Code (JavaFX application, kotlin):
class TempController {
#FXML
private lateinit var treeTable: TreeTableView<SkillTableDAO>
#FXML
private lateinit var colValue: TreeTableColumn<SkillTableDAO, String>
private val skillTree: MutableMap<Long, TreeItem<SkillTableDAO>> = ConcurrentHashMap()
#Suppress("unused")
fun initialize() {
colValue.setCellValueFactory {
ReadOnlyStringWrapper(it.value.value.getValue())
}
val treeRoot = TreeItem<SkillTableDAO>(null).apply { isExpanded = true }
treeTable.isShowRoot = false
treeTable.root = treeRoot
Pck_CmdSetSkill.listen { packet ->
Platform.runLater {
var node = skillTree[packet.id]
if (node != null) {
node.value.onPacket(packet)
// Packets goning unordered, so try to find parent
if ((node.parent == treeRoot || node.parent.value.id != node.value.parentId) && skillTree.containsKey(packet.parentId)) {
node.parent.children.remove(node)
skillTree[packet.parentId]!!.children.add(node)
}
} else {
node = TreeItem(SkillTableDAO(packet))
skillTree[packet.id] = node
(skillTree[packet.parentId] ?: treeRoot).children.add(node)
}
}
}
}
#Suppress("unused")
class SkillTableDAO(packet: Pck_CmdSetSkill.Packet) {
val id: Long = packet.id
val parentId: Long = packet.parentId
var value: Float = packet.value
fun onPacket(packet: Pck_CmdSetSkill.Packet): SkillTableDAO {
this.value = packet.value
return this
}
fun getValue() = value.toString()
}
}
The value of the cell remains in its original state when I change the values of the object (when Pck_CmdSetSkill.listen happens). What am I doing wrong?
I've tried few variants of observable, but fails... Also i've tried to it.value.value.value.toString() but no something new happend.
Pck_CmdSetSkill was called only initial, wrong code in another place =(

void can not converted to Unit when use kotlin in java code - android

I am working with kotlin and java together in my project, I have a class kotlin like bellow:
class AuthenticationPresenter #Inject constructor(
private val navigator: AuthenticationNavigator,
private val getCurrentServerInteractor: GetCurrentServerInteractor,
private val getAccountInteractor: GetAccountInteractor,
private val settingsRepository: SettingsRepository,
private val localRepository: LocalRepository,
private val tokenRepository: TokenRepository
) {
suspend fun loadCredentials(newServer: Boolean, callback: (authenticated: Boolean) -> Unit) {
val currentServer = getCurrentServerInteractor.get()
val serverToken = currentServer?.let { tokenRepository.get(currentServer) }
val settings = currentServer?.let { settingsRepository.get(currentServer) }
val account = currentServer?.let { getAccountInteractor.get(currentServer) }
account?.let {
localRepository.save(LocalRepository.CURRENT_USERNAME_KEY, account.userName)
}
if (newServer || currentServer == null || serverToken == null || settings == null || account?.userName == null) {
callback(false)
} else {
callback(true)
navigator.toChatList()
}
}
}
I am converting bellow code (kotlin) to java:
presenter.loadCredentials(newServer || deepLinkInfo != null) { authenticated ->
if (!authenticated) {
showServerInput(deepLinkInfo)
}
}
And this is my convert code to java but get me error:
presenter.loadCredentials((newServer || deepLinkInfo != null), authenticated ->{
if (!authenticated) {
showServerInput(deepLinkInfo);
}
});
But say me: Missing return statement
What can I use from this loadCredentials in java code?
Code of showServerInput:
fun showServerInput(deepLinkInfo: LoginDeepLinkInfo?) {
addFragment(TAG_SERVER_FRAGMENT, R.id.fragment_container, allowStateLoss = true) {
ServerFragment.newInstance(deepLinkInfo)
}
}
All the previous answers fail to include the part where you need to return an instance of Unit, once I did that I was able to get a similar issue fixed.
There is a slight issue with the original question in that "AA" cannot be returned and so would throw an error and instead you'd need to call a method.
Here's how to do it in the context of this question.
presenter.loadCredentials((newServer || deepLinkInfo != null), authenticated ->{
if (!authenticated) {
showServerInput(deepLinkInfo); // Here!
} else {
myOtherMethod();
}
return Unit.INSTANCE;
});
You need to return the result of showServerInput:
presenter.loadCredentials((newServer || deepLinkInfo != null), authenticated ->{
if (!authenticated) {
return showServerInput(deepLinkInfo); // Here!
} else {
return "AA";
}
});
Try this
presenter.loadCredentials((newServer || deepLinkInfo != null), authenticated ->{
if (!authenticated) {
showServerInput(deepLinkInfo);
}
});

Categories