Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion loans/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,5 @@ android {

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "com.smallcase.loans:sdk:3.1.1"
implementation "com.smallcase.loans:sdk-release-scg-v5-0-0-loans-v4-0-0-1df0c05:3.1.1-81-release"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.example.scloans

import android.util.Log
import com.smallcase.loans.data.listeners.Notification
import com.smallcase.loans.data.listeners.NotificationCenter
import com.smallcase.loans.core.external.ScLoanNotification
import io.flutter.embedding.engine.plugins.FlutterPlugin
import io.flutter.plugin.common.EventChannel


class ScLoanEventsHandler : FlutterPlugin {

private val TAG = "ScLoanEventsHandler"
private lateinit var eventChannel: EventChannel
private lateinit var eventStreamHandler: ScLoanEventsStreamHandler
private var notificationObserver: ((Notification) -> Unit)? = null

override fun onAttachedToEngine(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
setup(flutterPluginBinding)
}

override fun onDetachedFromEngine(binding: FlutterPlugin.FlutterPluginBinding) {
cleanup()
}

private fun setup(flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
eventStreamHandler = ScLoanEventsStreamHandler()
eventChannel = EventChannel(flutterPluginBinding.binaryMessenger, "scloans_events")
eventChannel.setStreamHandler(eventStreamHandler)

setupNotificationListener()
Log.d(TAG, "ScLoan events channel setup complete")
}

private fun setupNotificationListener() {
notificationObserver?.let { NotificationCenter.removeObserver(it) }

notificationObserver = { notification ->
try {
val jsonString = notification.userInfo?.get(ScLoanNotification.STRINGIFIED_PAYLOAD_KEY) as? String
if (jsonString != null) {
Log.d(TAG, "Sending notification to Flutter: $jsonString")
eventStreamHandler.sendEvent(jsonString)
} else {
Log.w(TAG, "Notification has no JSON payload")
}
} catch (e: Exception) {
Log.e(TAG, "Error processing notification: ${e.message}")
eventStreamHandler.sendError("NOTIFICATION_PARSE_ERROR", e.message, e.toString())
}
}

notificationObserver?.let {
NotificationCenter.addObserver(it)
Log.d(TAG, "Notification observer added")
}
}

private fun cleanup() {
try {
notificationObserver?.let {
NotificationCenter.removeObserver(it)
Log.d(TAG, "Notification observer removed")
}
} catch (e: Exception) {
Log.e(TAG, "Error removing notification observer: ${e.message}")
}

notificationObserver = null
eventChannel.setStreamHandler(null)
Log.d(TAG, "SCGateway events cleanup complete")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.example.scloans

import android.os.Handler
import android.os.Looper
import io.flutter.plugin.common.EventChannel

class ScLoanEventsStreamHandler: EventChannel.StreamHandler {

private var eventSink: EventChannel.EventSink? = null
private val mainHandler = Handler(Looper.getMainLooper())

override fun onListen(arguments: Any?, events: EventChannel.EventSink?) {
eventSink = events
}

override fun onCancel(arguments: Any?) {
eventSink = null
}

// Call this method to send data to Flutter
fun sendEvent(data: Any) {
mainHandler.post {
eventSink?.success(data)
}
}

// Call this method to send error to Flutter
fun sendError(errorCode: String, errorMessage: String?, errorDetails: Any? = null) {
mainHandler.post {
eventSink?.error(errorCode, errorMessage, errorDetails)
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,14 @@ import io.flutter.embedding.engine.plugins.FlutterPlugin
import com.google.gson.Gson
import com.smallcase.loans.core.external.*
import com.smallcase.loans.core.external.ScLoanEnvironment
import com.smallcase.loans.core.external.ScLoan
import com.smallcase.loans.core.external.ScLoanNotification
import com.smallcase.loans.data.listeners.Notification
import com.smallcase.loans.data.listeners.NotificationCenter
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.EventChannel
import io.flutter.embedding.engine.plugins.activity.ActivityAware
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding
import org.json.JSONObject
Expand All @@ -26,20 +31,26 @@ class ScLoanFlutterPlugin: FlutterPlugin, MethodCallHandler, ActivityAware {
private lateinit var activity: Activity
private lateinit var scLoansChannel: MethodChannel
private val uiThreadHandler: Handler = Handler(Looper.getMainLooper())
private var scLoanEventsHandler: ScLoanEventsHandler? = null


override fun onAttachedToEngine(@NonNull flutterPluginBinding: FlutterPlugin.FlutterPluginBinding) {
this.context = flutterPluginBinding.applicationContext

scLoansChannel = MethodChannel(flutterPluginBinding.binaryMessenger, "scloans")
scLoansChannel.setMethodCallHandler(this)
// scLoansChannel.setMethodCallHandler(ScLoanFlutterPlugin(getActivity = {
// activity
// }))


scLoanEventsHandler = ScLoanEventsHandler()
scLoanEventsHandler?.onAttachedToEngine(flutterPluginBinding)

}

override fun onDetachedFromEngine(@NonNull binding: FlutterPlugin.FlutterPluginBinding) {
scLoansChannel.setMethodCallHandler(null)

scLoanEventsHandler?.onDetachedFromEngine(binding)
scLoanEventsHandler = null
}

override fun onAttachedToActivity(binding: ActivityPluginBinding) {
Expand Down
43 changes: 43 additions & 0 deletions loans/ios/Classes/ScLoanEventsHandler.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import Foundation
import Flutter
import Loans

class ScLoanEventsHandler: NSObject {

private var eventChannel: FlutterEventChannel?
private var eventStreamHandler: ScLoanEventsStreamHandler?

func setup(with registrar: FlutterPluginRegistrar) {
print("Setting up SCLoans events channel...")

eventStreamHandler = ScLoanEventsStreamHandler()
eventChannel = FlutterEventChannel(name: "scloans_events", binaryMessenger: registrar.messenger())
eventChannel?.setStreamHandler(eventStreamHandler)

setupNotificationListener()
print("SCLoans events channel setup complete")
}

private func setupNotificationListener() {
NotificationCenter.default.addObserver(
forName: ScLoan.scLoansNotificationName,
object: nil,
queue: .main
) { [weak self] notification in
self?.handleNotification(notification)
}
}

private func handleNotification(_ notification: Notification) {
guard let eventStreamHandler = eventStreamHandler,
let userInfo = notification.userInfo,
let jsonString = userInfo[ScLoanNotification.strigifiedPayloadKey] as? String else { return }

eventStreamHandler.sendEvent(jsonString)
}

deinit {
NotificationCenter.default.removeObserver(self)
eventChannel?.setStreamHandler(nil)
}
}
22 changes: 22 additions & 0 deletions loans/ios/Classes/ScLoanEventsStreamHandler.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import Foundation
import Flutter

class ScLoanEventsStreamHandler: NSObject, FlutterStreamHandler {
private var eventSink: FlutterEventSink?

func onListen(withArguments arguments: Any?, eventSink events: @escaping FlutterEventSink) -> FlutterError? {
self.eventSink = events
return nil
}

func onCancel(withArguments arguments: Any?) -> FlutterError? {
self.eventSink = nil
return nil
}

func sendEvent(_ event: String) {
DispatchQueue.main.async { [weak self] in
self?.eventSink?(event)
}
}
}
13 changes: 10 additions & 3 deletions loans/ios/Classes/ScLoanFlutterPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,19 @@ public class SwiftScLoanFlutterPlugin: NSObject, FlutterPlugin {
@MainActor
let currentViewController: UIViewController = (UIApplication.shared.delegate?.window??.rootViewController)!

private var eventsHandler: ScLoanEventsHandler?

public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "scloans", binaryMessenger: registrar.messenger())
let instance = SwiftScLoanFlutterPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)

instance.eventsHandler = ScLoanEventsHandler()
instance.eventsHandler?.setup(with: registrar)

print("SwiftScLoansFlutterPlugin with events handler registered successfully")
}

public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {

guard let args = call.arguments as? Dictionary<String, Any> else { return }
Expand Down Expand Up @@ -148,7 +155,7 @@ public class SwiftScLoanFlutterPlugin: NSObject, FlutterPlugin {
result("Flutter method not implemented on iOS")
}
}

// This conversion is vital because only by passing a FlutterError object to the result:FlutterResult call will the error be thrown in the catch block on the dart side
private func convertErrorToFlutterError(error: ScLoanError) -> FlutterError {

Expand Down Expand Up @@ -196,7 +203,7 @@ extension Dictionary {

} catch let dictionaryError as NSError {

print("Unable to convert dictionary to json String :\(dictionaryError)")
print("Unable to convert dictionary to json String :\(dictionaryError)")

return nil
}
Expand Down
2 changes: 1 addition & 1 deletion loans/ios/scloans.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ A new flutter plugin project.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'EXCLUDED_ARCHS[sdk=iphonesimulator*]' => 'i386' }
s.swift_version = '5.0'

s.dependency 'SCLoans', '6.0.0'
s.dependency 'SCLoans', '6.0.1'
end
1 change: 1 addition & 0 deletions loans/lib/sc_loan.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:flutter/services.dart';
import 'dart:convert';
import 'sc_loan_props.dart';
import 'sc_loan_responses.dart';
import 'platform_exception_ext.dart';
Expand Down
52 changes: 52 additions & 0 deletions loans/lib/sc_loan_events.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/services.dart';

class ScLoanEvents {
static const EventChannel _eventChannel = EventChannel('scloans_events');
static StreamSubscription<dynamic>? _subscription;
static final StreamController<String> _eventController =
StreamController<String>.broadcast();

/// Stream of SCLoan events (raw JSON strings)
static Stream<String> get eventStream => _eventController.stream;

/// Start listening to SCLoan events
static void startListening() {
if (_subscription != null) return;

_subscription = _eventChannel.receiveBroadcastStream().listen(
(dynamic event) {
if (event is String) {
print('SCLoan event stream: $event');
_eventController.add(event);
}
},
onError: (dynamic error) {
print('SCLoan event stream error: $error');
},
);
}

/// Stop listening to SCLoan events
static void stopListening() {
_subscription?.cancel();
_subscription = null;
}

/// Dispose resources
static void dispose() {
stopListening();
_eventController.close();
}

/// Parse event data from JSON string
static Map<String, dynamic>? parseEvent(String jsonString) {
try {
return json.decode(jsonString) as Map<String, dynamic>;
} catch (e) {
print('Error parsing event JSON: $e');
return null;
}
}
}
2 changes: 1 addition & 1 deletion scgateway/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,5 @@ android {
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

implementation "com.smallcase.gateway:sdk:4.3.0"
implementation "com.smallcase.gateway:sdk-release-scg-v5-0-0-loans-v4-0-0-1df0c05:4.3.0-3183-release"
}
Loading