diff --git a/.gitignore b/.gitignore
index f6a3ad6d..57bb88e2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,4 +16,5 @@ app-iOS/app-iOS.xcworkspace/*
*.plist
.kotlin/
-venv/
\ No newline at end of file
+venv/
+daraja/swiftpackage
\ No newline at end of file
diff --git a/app-desktop/.gitignore b/app-desktop/.gitignore
deleted file mode 100644
index 42afabfd..00000000
--- a/app-desktop/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-/build
\ No newline at end of file
diff --git a/app-desktop/build.gradle.kts b/app-desktop/build.gradle.kts
deleted file mode 100644
index a81edb8c..00000000
--- a/app-desktop/build.gradle.kts
+++ /dev/null
@@ -1,22 +0,0 @@
-plugins {
- alias(libs.plugins.jvm)
- alias(libs.plugins.compose)
- alias(libs.plugins.compose.compiler)
-}
-
-repositories {
- mavenCentral()
- maven("https://maven.pkg.jetbrains.space/public/p/compose/dev")
- google()
-}
-
-dependencies {
- implementation(project(":daraja"))
- implementation(compose.desktop.currentOs)
-}
-
-compose.desktop {
- application {
- mainClass = "MainKt"
- }
-}
diff --git a/app-desktop/src/main/java/com/vickikbt/app_desktop/Main.kt b/app-desktop/src/main/java/com/vickikbt/app_desktop/Main.kt
deleted file mode 100644
index 97c42fc1..00000000
--- a/app-desktop/src/main/java/com/vickikbt/app_desktop/Main.kt
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2022 Daraja Multiplatform
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.vickikbt.app_desktop
-
-import androidx.compose.ui.window.application
-import ui.screens.main.MainScreen
-
-fun main() {
- return application {
- MainScreen(applicationScope = this)
- }
-}
diff --git a/app-desktop/src/main/java/com/vickikbt/app_desktop/ui/screens/home/HomeScreen.kt b/app-desktop/src/main/java/com/vickikbt/app_desktop/ui/screens/home/HomeScreen.kt
deleted file mode 100644
index 09f39fcd..00000000
--- a/app-desktop/src/main/java/com/vickikbt/app_desktop/ui/screens/home/HomeScreen.kt
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 2022 Daraja Multiplatform
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.vickikbt.app_desktop.ui.screens.home
-
-import androidx.compose.desktop.ui.tooling.preview.Preview
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.text.KeyboardOptions
-import androidx.compose.material.Button
-import androidx.compose.material.MaterialTheme
-import androidx.compose.material.OutlinedTextField
-import androidx.compose.material.Text
-import androidx.compose.material.TextFieldDefaults
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.text.input.KeyboardType
-import androidx.compose.ui.text.style.TextAlign
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-import com.vickbt.darajakmp.Daraja
-import com.vickbt.darajakmp.utils.onFailure
-import com.vickbt.darajakmp.utils.onSuccess
-import com.vickikbt.app_android.ui.theme.DarajaKmpTheme
-
-@Composable
-fun HomeScreen() {
- val tillNumber by remember { mutableStateOf("174379") }
- var amount by remember { mutableStateOf(1) }
- var phoneNumber by remember { mutableStateOf("0714091304") }
-
- val daraja by remember {
- mutableStateOf(
- Daraja.Builder()
- .setConsumerKey("zg1m1CbMGx8E2BqVThHIJHFMWSnVJ4XA")
- .setConsumerSecret("z4CAY2TUw6rprEvy")
- .setPassKey("bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919")
- .isSandbox()
- .build(),
- )
- }
-
- Box(
- modifier =
- Modifier
- .fillMaxSize()
- .padding(vertical = 16.dp, horizontal = 8.dp),
- ) {
- Text(
- modifier =
- Modifier
- .align(Alignment.TopCenter)
- .padding(horizontal = 2.dp),
- text = "Daraja Multiplatform Desktop",
- fontWeight = FontWeight.ExtraBold,
- fontSize = 32.sp,
- textAlign = TextAlign.Center,
- )
-
- Column(
- modifier = Modifier.align(Alignment.Center),
- horizontalAlignment = Alignment.CenterHorizontally,
- verticalArrangement =
- Arrangement.spacedBy(
- space = 42.dp,
- alignment = Alignment.CenterVertically,
- ),
- ) {
- OutlinedTextField(
- modifier = Modifier.fillMaxWidth(.8f),
- value = amount.toString(),
- onValueChange = { amount = it.toInt() },
- singleLine = true,
- maxLines = 1,
- textStyle =
- TextStyle(
- fontSize = 20.sp,
- color = MaterialTheme.colors.onBackground,
- ),
- label = { Text(text = "Amount") },
- colors = TextFieldDefaults.outlinedTextFieldColors(focusedBorderColor = MaterialTheme.colors.primary),
- keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number),
- )
-
- OutlinedTextField(
- modifier = Modifier.fillMaxWidth(.8f),
- value = phoneNumber,
- onValueChange = { phoneNumber = it },
- singleLine = true,
- maxLines = 1,
- textStyle =
- TextStyle(
- fontSize = 20.sp,
- color = MaterialTheme.colors.onBackground,
- ),
- label = { Text(text = "Phone Number") },
- colors = TextFieldDefaults.outlinedTextFieldColors(focusedBorderColor = MaterialTheme.colors.primary),
- keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Phone),
- )
- }
-
- Button(
- modifier = Modifier.align(Alignment.BottomCenter),
- onClick = { initiateMpesaStk(daraja, tillNumber, amount, phoneNumber) },
- ) {
- Text(text = "Make Payment", fontSize = 20.sp)
- }
- }
-}
-
-fun initiateMpesaStk(
- daraja: Daraja,
- tillNumber: String,
- amount: Int,
- phoneNumber: String,
-) {
- daraja.mpesaExpress(
- businessShortCode = tillNumber,
- amount = amount,
- phoneNumber = phoneNumber,
- transactionDesc = "Mpesa payment",
- callbackUrl = "https://mydomain.com/path",
- accountReference = "Daraja KMP Android",
- ).onSuccess {
- println(message = "On success block called: $it")
- }.onFailure {
- println(message = "On failure block called: $it")
- }
-}
-
-@Preview
-@Composable
-fun DefaultPreview() {
- DarajaKmpTheme {
- HomeScreen()
- }
-}
diff --git a/app-desktop/src/main/java/com/vickikbt/app_desktop/ui/screens/main/MainScreen.kt b/app-desktop/src/main/java/com/vickikbt/app_desktop/ui/screens/main/MainScreen.kt
deleted file mode 100644
index 43ce3fee..00000000
--- a/app-desktop/src/main/java/com/vickikbt/app_desktop/ui/screens/main/MainScreen.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2022 Daraja Multiplatform
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package ui.screens.main
-
-import androidx.compose.material.MaterialTheme
-import androidx.compose.material.Surface
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.unit.Dp
-import androidx.compose.ui.window.ApplicationScope
-import androidx.compose.ui.window.Window
-import androidx.compose.ui.window.WindowPosition
-import androidx.compose.ui.window.rememberWindowState
-import com.vickikbt.app_android.ui.theme.DarajaKmpTheme
-import com.vickikbt.app_desktop.ui.screens.home.HomeScreen
-
-@Composable
-fun MainScreen(applicationScope: ApplicationScope) {
- Window(
- onCloseRequest = { applicationScope.exitApplication() },
- title = "Daraja Multiplatform Desktop",
- state =
- rememberWindowState(
- position = WindowPosition.Aligned(Alignment.Center),
- width = Dp.Unspecified,
- height = Dp.Unspecified,
- ),
- ) {
- DarajaKmpTheme(darkTheme = true) {
- Surface(color = MaterialTheme.colors.surface) {
- HomeScreen()
- }
- }
- }
-}
diff --git a/app-desktop/src/main/java/com/vickikbt/app_desktop/ui/theme/Color.kt b/app-desktop/src/main/java/com/vickikbt/app_desktop/ui/theme/Color.kt
deleted file mode 100644
index 8cc531e5..00000000
--- a/app-desktop/src/main/java/com/vickikbt/app_desktop/ui/theme/Color.kt
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2022 Daraja Multiplatform
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.vickikbt.app_android.ui.theme
-
-import androidx.compose.ui.graphics.Color
-
-val Purple80 = Color(0xFFD0BCFF)
-val PurpleGrey80 = Color(0xFFCCC2DC)
-val Pink80 = Color(0xFFEFB8C8)
-
-val Purple40 = Color(0xFF6650a4)
-val PurpleGrey40 = Color(0xFF625b71)
-val Pink40 = Color(0xFF7D5260)
diff --git a/app-desktop/src/main/java/com/vickikbt/app_desktop/ui/theme/Theme.kt b/app-desktop/src/main/java/com/vickikbt/app_desktop/ui/theme/Theme.kt
deleted file mode 100644
index 6a610f30..00000000
--- a/app-desktop/src/main/java/com/vickikbt/app_desktop/ui/theme/Theme.kt
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2022 Daraja Multiplatform
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.vickikbt.app_android.ui.theme
-
-import androidx.compose.foundation.isSystemInDarkTheme
-import androidx.compose.material.MaterialTheme
-import androidx.compose.material.darkColors
-import androidx.compose.material.lightColors
-import androidx.compose.runtime.Composable
-
-private val DarkColorScheme =
- darkColors(
- primary = Purple80,
- secondary = PurpleGrey80,
- )
-
-private val LightColorScheme =
- lightColors(
- primary = Purple40,
- secondary = PurpleGrey40,
- /* Other default colors to override
- background = Color(0xFFFFFBFE),
- surface = Color(0xFFFFFBFE),
- onPrimary = Color.White,
- onSecondary = Color.White,
- onTertiary = Color.White,
- onBackground = Color(0xFF1C1B1F),
- onSurface = Color(0xFF1C1B1F),
- */
- )
-
-@Composable
-fun DarajaKmpTheme(
- darkTheme: Boolean = isSystemInDarkTheme(),
- content: @Composable () -> Unit,
-) {
- val colorScheme =
- when {
- darkTheme -> DarkColorScheme
- else -> LightColorScheme
- }
-
- MaterialTheme(
- colors = colorScheme,
- typography = Typography,
- content = content,
- )
-}
diff --git a/app-desktop/src/main/java/com/vickikbt/app_desktop/ui/theme/Type.kt b/app-desktop/src/main/java/com/vickikbt/app_desktop/ui/theme/Type.kt
deleted file mode 100644
index 8bb67f83..00000000
--- a/app-desktop/src/main/java/com/vickikbt/app_desktop/ui/theme/Type.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2022 Daraja Multiplatform
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.vickikbt.app_android.ui.theme
-
-import androidx.compose.material.Typography
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.sp
-
-// Set of Material typography styles to start with
-val Typography =
- Typography(
- h4 =
- TextStyle(
- fontFamily = FontFamily.Default,
- fontWeight = FontWeight.Normal,
- fontSize = 16.sp,
- lineHeight = 24.sp,
- letterSpacing = 0.5.sp,
- ),
- /* Other default text styles to override
- titleLarge = TextStyle(
- fontFamily = FontFamily.Default,
- fontWeight = FontWeight.Normal,
- fontSize = 22.sp,
- lineHeight = 28.sp,
- letterSpacing = 0.sp
- ),
- labelSmall = TextStyle(
- fontFamily = FontFamily.Default,
- fontWeight = FontWeight.Medium,
- fontSize = 11.sp,
- lineHeight = 16.sp,
- letterSpacing = 0.5.sp
- )
- */
- )
diff --git a/app-iOS/Podfile b/app-iOS/Podfile
deleted file mode 100644
index 54e587ba..00000000
--- a/app-iOS/Podfile
+++ /dev/null
@@ -1,4 +0,0 @@
-target 'app-iOS' do
- use_frameworks!
- platform :ios, '14.1'
-end
\ No newline at end of file
diff --git a/app-iOS/app-iOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/app-iOS/app-iOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
deleted file mode 100644
index 18d98100..00000000
--- a/app-iOS/app-iOS.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
- IDEDidComputeMac32BitWarning
-
-
-
diff --git a/app-iOS/app-iOS/ContentView.swift b/app-iOS/app-iOS/ContentView.swift
deleted file mode 100644
index bff2fcad..00000000
--- a/app-iOS/app-iOS/ContentView.swift
+++ /dev/null
@@ -1,99 +0,0 @@
-//
-// ContentView.swift
-// app-iOS
-//
-// Created by Victor Kabata on 15/08/2023.
-//
-
-import DarajaMultiplatform
-import SwiftUI
-
-struct ContentView: View {
-
- @State private var amount: Int32 = 1
- @FocusState private var isAmountTextFieldFocused: Bool
-
- @State private var phoneNumber: String = ""
- @FocusState private var isPhoneTextFieldFocused: Bool
-
- var daraja=Daraja(
- consumerKey: "MAYA4V9yTveRBa3yP1syMfkgGzDNqSxO",
- consumerSecret: "WU6A0ojDuSJUSP77",
- passKey:"bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919",
- environment: DarajaEnvironment.sandboxEnvironment)
-
- var body: some View {
- VStack {
-
- // Amount textfield
- TextField("Amount", text: .init(get: {"\(amount)"}, set: {
- if let newValue = Int32($0) {
- amount = newValue
- }
- }))
- .padding()
- .accentColor(.green)
- .background(.white)
- .keyboardType(.numberPad)
- .overlay(
- RoundedRectangle(cornerRadius: 10)
- .stroke(isAmountTextFieldFocused ? Color.green: Color.gray.opacity(0.5), lineWidth: 1)
- )
- .cornerRadius(10)
- .shadow(color: Color.gray.opacity(0.4), radius: 4, x: 0, y: 2)
- .padding()
- .focused($isAmountTextFieldFocused)
-
- // Phone Number textfield
- TextField("Phone Number", text: $phoneNumber)
- .padding()
- .accentColor(.green)
- .background(.white)
- .keyboardType(.phonePad)
- .overlay(
- RoundedRectangle(cornerRadius: 10)
- .stroke(isPhoneTextFieldFocused ? Color.green:Color.gray.opacity(0.5), lineWidth: 1)
- )
- .cornerRadius(10)
- .shadow(color: Color.gray.opacity(0.4), radius: 4, x: 0, y: 2)
- .padding()
- .focused($isPhoneTextFieldFocused)
-
- // Pay Button
- Button(action: {
- initiateMpesaPayment(daraja: daraja, businessShortCode: "174379", amount: amount, phoneNumber: phoneNumber, transactionDesc: "M-Pesa payment", callbackUrl: "https://mydomain.com/path", accountReference: "174379")
- }) {
- Image(systemName: "plus")
- .padding(20)
- .background(Color.green)
- .foregroundColor(.white)
- .clipShape(Circle())
- }
- }.padding(.horizontal,24)
-
- }
-}
-
-func initiateMpesaPayment(daraja:Daraja,
- businessShortCode: String,
- amount: Int32,
- phoneNumber: String,
- transactionDesc: String,
- callbackUrl: String,
- accountReference: String){
-
- let response=daraja.initiateMpesaExpressPayment(businessShortCode: businessShortCode, amount: amount, phoneNumber: phoneNumber,transactionType: DarajaTransactionType.customerpaybillonline, transactionDesc: "M-Pesa payment", callbackUrl: "https://mydomain.com/path", accountReference: "Daraja KMP iOS")
-
- response.onSuccess(action: {data in
- print(data.self)
- })
- .onFailure(action: {error in
- print(error)
- })
-}
-
-struct ContentView_Previews: PreviewProvider {
- static var previews: some View {
- ContentView()
- }
-}
diff --git a/build.gradle.kts b/build.gradle.kts
index fdd253b2..2ca54341 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,7 +4,6 @@ plugins {
alias(libs.plugins.android.application) apply false
alias(libs.plugins.multiplatform) apply false
alias(libs.plugins.jvm) apply false
- alias(libs.plugins.nativeCocoapod) apply false
alias(libs.plugins.compose.compiler) apply false
alias(libs.plugins.ktLint)
diff --git a/daraja/build.gradle.kts b/daraja/build.gradle.kts
index 4d4b0c34..14a40982 100644
--- a/daraja/build.gradle.kts
+++ b/daraja/build.gradle.kts
@@ -25,7 +25,6 @@ fun isNonStable(version: String): Boolean {
}
plugins {
- alias(libs.plugins.nativeCocoapod)
alias(libs.plugins.multiplatform)
alias(libs.plugins.android.library)
alias(libs.plugins.kotlinX.serialization)
@@ -43,23 +42,19 @@ kotlin {
kotlin.applyDefaultHierarchyTemplate()
androidTarget {
- publishLibraryVariants("release")
+ publishLibraryVariants("debug", "release")
compilerOptions {
jvmTarget.set(JvmTarget.JVM_1_8)
}
}
- iosX64()
- iosArm64()
- iosSimulatorArm64()
-
- cocoapods {
- summary = "Daraja API Swift Wrapper built using Kotlin Multiplatform"
- homepage = "https://github.com/VictorKabata/DarajaMultiplatform.git"
- version = "1.0"
- ios.deploymentTarget = "14.1"
- framework {
+ listOf(
+ iosX64(),
+ iosArm64(),
+ iosSimulatorArm64(),
+ ).forEach {
+ it.binaries.framework {
baseName = "DarajaMultiplatform"
isStatic = true
}
@@ -232,7 +227,7 @@ multiplatformSwiftPackage {
packageName("DarajaMultiplatform")
swiftToolsVersion("5.3")
targetPlatforms {
- iOS { v("14.1") }
+ iOS { v("13") }
}
}
diff --git a/daraja/src/commonMain/kotlin/com/vickbt/darajakmp/Daraja.kt b/daraja/src/commonMain/kotlin/com/vickbt/darajakmp/Daraja.kt
index d717af47..6c3af625 100644
--- a/daraja/src/commonMain/kotlin/com/vickbt/darajakmp/Daraja.kt
+++ b/daraja/src/commonMain/kotlin/com/vickbt/darajakmp/Daraja.kt
@@ -18,8 +18,6 @@ package com.vickbt.darajakmp
import com.vickbt.darajakmp.network.DarajaApiService
import com.vickbt.darajakmp.network.DarajaHttpClientFactory
-import com.vickbt.darajakmp.network.models.AccountBalanceRequest
-import com.vickbt.darajakmp.network.models.AccountBalanceResponse
import com.vickbt.darajakmp.network.models.C2BRegistrationRequest
import com.vickbt.darajakmp.network.models.C2BRequest
import com.vickbt.darajakmp.network.models.C2BResponse
@@ -35,7 +33,6 @@ import com.vickbt.darajakmp.network.models.QueryMpesaExpressRequest
import com.vickbt.darajakmp.network.models.QueryMpesaExpressResponse
import com.vickbt.darajakmp.utils.C2BResponseType
import com.vickbt.darajakmp.utils.DarajaEnvironment
-import com.vickbt.darajakmp.utils.DarajaIdentifierType
import com.vickbt.darajakmp.utils.DarajaResult
import com.vickbt.darajakmp.utils.DarajaTransactionCode
import com.vickbt.darajakmp.utils.DarajaTransactionType
@@ -44,7 +41,6 @@ import com.vickbt.darajakmp.utils.getDarajaPassword
import com.vickbt.darajakmp.utils.getDarajaPhoneNumber
import com.vickbt.darajakmp.utils.getDarajaTimestamp
import io.ktor.client.HttpClient
-import io.ktor.util.encodeBase64
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.runBlocking
@@ -354,46 +350,4 @@ class Daraja(
darajaApiService.c2b(c2bRequest = c2bRequest)
}
-
- /**Request the account balance of a short code. This can be used for both B2C, buy goods and pay bill accounts.
- *
- * @param [initiator] This is the credential/username used to authenticate the transaction request
- * @param [initiatorPassword] This is the credential/password used to authenticate the account balance request
- * @param [commandId] A unique command is passed to the M-PESA system. Max length is 64.
- * @param [partyA] The shortcode of the organization querying for the account balance.
- * @param [identifierType] Type of organization querying for the account balance.
- * @param [remarks] Comments that are sent along with the transaction
- * @param [queueTimeOutURL] The end-point that receives a timeout message.
- * @param [resultURL] It indicates the destination URL which Daraja should send the result message to.
- *
- * @return [AccountBalanceResponse]
- * */
- internal fun accountBalance(
- initiator: String,
- initiatorPassword: String,
- commandId: String = "AccountBalance",
- partyA: Int,
- identifierType: DarajaIdentifierType,
- remarks: String = "Account balance request",
- queueTimeOutURL: String,
- resultURL: String,
- ): DarajaResult =
- runBlocking(Dispatchers.IO) {
- val key = initiator + initiatorPassword
- val securityCredential = key.encodeBase64()
-
- val accountBalanceRequest =
- AccountBalanceRequest(
- initiator = initiator,
- securityCredential = securityCredential,
- commandId = commandId,
- partyA = partyA,
- identifierType = if (identifierType == DarajaIdentifierType.TILL_NUMBER) 2 else 4,
- remarks = remarks,
- queueTimeOutURL = queueTimeOutURL,
- resultURL = resultURL,
- )
-
- darajaApiService.accountBalance(accountBalanceRequest = accountBalanceRequest)
- }
}
diff --git a/daraja/src/commonMain/kotlin/com/vickbt/darajakmp/network/DarajaApiService.kt b/daraja/src/commonMain/kotlin/com/vickbt/darajakmp/network/DarajaApiService.kt
index a24dc7a0..70388cf5 100644
--- a/daraja/src/commonMain/kotlin/com/vickbt/darajakmp/network/DarajaApiService.kt
+++ b/daraja/src/commonMain/kotlin/com/vickbt/darajakmp/network/DarajaApiService.kt
@@ -16,8 +16,6 @@
package com.vickbt.darajakmp.network
-import com.vickbt.darajakmp.network.models.AccountBalanceRequest
-import com.vickbt.darajakmp.network.models.AccountBalanceResponse
import com.vickbt.darajakmp.network.models.C2BRegistrationRequest
import com.vickbt.darajakmp.network.models.C2BRequest
import com.vickbt.darajakmp.network.models.C2BResponse
@@ -129,7 +127,7 @@ internal class DarajaApiService(
}.body()
}
- suspend fun c2bRegistration(c2bRegistrationRequest: C2BRegistrationRequest): DarajaResult =
+ internal suspend fun c2bRegistration(c2bRegistrationRequest: C2BRegistrationRequest): DarajaResult =
darajaSafeApiCall {
val accessToken =
inMemoryCache.get(1) {
@@ -154,17 +152,4 @@ internal class DarajaApiService(
setBody(c2bRequest)
}.body()
}
-
- internal suspend fun accountBalance(accountBalanceRequest: AccountBalanceRequest): DarajaResult =
- darajaSafeApiCall {
- val accessToken =
- inMemoryCache.get(1) {
- fetchAccessToken().getOrThrow()
- }
-
- return@darajaSafeApiCall httpClient.post(urlString = DarajaEndpoints.ACCOUNT_BALANCE) {
- headers { append(HttpHeaders.Authorization, "Bearer ${accessToken.accessToken}") }
- setBody(accountBalanceRequest)
- }.body()
- }
}
diff --git a/daraja/src/commonMain/kotlin/com/vickbt/darajakmp/utils/DarajaConfigs.kt b/daraja/src/commonMain/kotlin/com/vickbt/darajakmp/utils/DarajaConfigs.kt
index 65a98450..1445ff71 100644
--- a/daraja/src/commonMain/kotlin/com/vickbt/darajakmp/utils/DarajaConfigs.kt
+++ b/daraja/src/commonMain/kotlin/com/vickbt/darajakmp/utils/DarajaConfigs.kt
@@ -48,13 +48,13 @@ enum class C2BResponseType {
/**
* @param [BG] Pay Merchant (Buy Goods).
*
- * @param [WA]: Withdraw Cash at Agent Till.
+ * @param [WA] Withdraw Cash at Agent Till.
*
- * @param [PB]: Paybill or Business number.
+ * @param [PB] Paybill or Business number.
*
- * @param [SM]: Send Money(Mobile number)
+ * @param [SM] Send Money(Mobile number)
*
- * @param [SB]: Sent to Business. Business number CPI in MSISDN format.*/
+ * @param [SB] Sent to Business. Business number CPI in MSISDN format.*/
enum class DarajaTransactionCode {
BG,
WA,
diff --git a/daraja/src/commonTest/kotlin/com/vickbt/darajakmp/utils/UtilsTest.kt b/daraja/src/commonTest/kotlin/com/vickbt/darajakmp/utils/UtilsTest.kt
index 5122dc61..a550e9f6 100644
--- a/daraja/src/commonTest/kotlin/com/vickbt/darajakmp/utils/UtilsTest.kt
+++ b/daraja/src/commonTest/kotlin/com/vickbt/darajakmp/utils/UtilsTest.kt
@@ -122,10 +122,13 @@ class UtilsTest {
@Test
fun `phone number with spaces are formatted correctly`() =
runTest {
- val phoneNumbers = listOf("0 714091 30 3", " + 2 547 140 913 03", "2 5 4714 091 30 3 ")
+ val phoneNumbers =
+ listOf("0 714091 30 3", " + 2 547 140 913 03", "2 5 4714 091 30 3 ")
val expectedPhoneNumbers = listOf("254714091303", "254714091303", "254714091303")
- assertThat(phoneNumbers.map { it.getDarajaPhoneNumber() }).isEqualTo(expectedPhoneNumbers)
+ assertThat(phoneNumbers.map { it.getDarajaPhoneNumber() }).isEqualTo(
+ expectedPhoneNumbers,
+ )
}
@Test
@@ -145,4 +148,13 @@ class UtilsTest {
assertThat(timeUnit.asFormattedWithZero()).isEqualTo(expectedTimeUnit)
}
+
+ @Test
+ fun `capitalize returns strings in title case`() =
+ runTest {
+ val wordList = listOf("heLlo", "WorlD", "DARAJA", "kmp", "DaRaJa", "2")
+ val expectedWordList = listOf("Hello", "World", "Daraja", "Kmp", "Daraja", "2")
+
+ assertThat(wordList.map { it.capitalize() }).isEqualTo(expectedWordList)
+ }
}
diff --git a/docs/kotlin.md b/docs/kotlin.md
index 8574b6c1..18f6b9ce 100644
--- a/docs/kotlin.md
+++ b/docs/kotlin.md
@@ -1,14 +1,16 @@
-# Kotlin SDK
+# __Kotlin SDK__
## Getting Started
-To get started with Daraja Multiplatform SDK, you will need to [create a Daraja API account](https://developer.safaricom.co.ke/) on the Daraja API portal and [set up a new test application](https://developer.safaricom.co.ke/MyApps).
+To get started with Daraja Multiplatform SDK, you will need
+to [create a Daraja API account](https://developer.safaricom.co.ke/) on the Daraja API portal
+and [set up a new test application](https://developer.safaricom.co.ke/MyApps).
Once you have access to the created test app, retrieve the ___Consumer Key___, ___Consumer Secret___ and ___Passkey___.
## Installation
-- In Android projects, add the following dependency in the app/feature module gradle file:
+- In an Android projects, add the following dependency in the app/feature module gradle file:
```Kotlin hl_lines="2"
dependencies {
@@ -31,9 +33,14 @@ kotlin {
## Setting Up
- Add the Consumer Key, Consumer Secret and Passkey to your project's environment secrets or local.properties file.
-> To protect your sensitive API keys, it's recommended to store your Consumer Key, Consumer Secret, and Passkey in your project's environment secrets or a local properties file (outside of version control). This ensures they are not accidentally exposed in public repositories.
-- Instantiate a `Daraja` object, providing the necessary environment variables. This Daraja instance serves as the entry point for various M-Pesa operations. Core functionalities include obtaining an access token required for subsequent API calls and initiating M-Pesa Express STK push requests.
+> To protect your sensitive API keys, it's recommended to store your Consumer Key, Consumer Secret, and Passkey in your
+> project's environment secrets or a local properties file (outside of version control). This ensures they are not
+> accidentally exposed in public repositories.
+
+- Instantiate a `Daraja` object, providing the necessary environment variables. This Daraja instance serves as the entry
+ point for various M-Pesa operations. Core functionalities include obtaining an access token required for subsequent
+ API calls and initiating M-Pesa Express STK push requests.
```Kotlin
val daraja: Daraja = Daraja.Builder()
@@ -43,7 +50,10 @@ val daraja: Daraja = Daraja.Builder()
.isProduction() // Optional. Will default to sandbox_mode = true
.build()
```
-> Daraja Multiplatform includes built-in network logging, which is active by default in sandbox mode but disabled in production mode. To inspect network requests and responses, view logs in Android Studio's Logcat under the __Daraja Multiplatform__ tag.
+
+> Daraja Multiplatform includes built-in network logging, which is active by default in sandbox mode but disabled in
+> production mode. To inspect network requests and responses, view logs in Android Studio's Logcat under the __Daraja
+Multiplatform__ tag.
## Usage
@@ -66,19 +76,19 @@ accessTokenResult.onSuccess { accessToken ->
- To initiate M-Pesa Express(Lipa na M-Pesa Online) STK request, invoke the `mpesaExpress` function:
```Kotlin
-val darajaPaymentResponse: DarajaResult = daraja.mpesaExpress(
- businessShortCode = "174379",
- amount = 1,
- phoneNumber = "07xxxxxxxx", // or +2547xxxxxxxx or 2547xxxxxxxx
- transactionDesc = "M-Pesa payment",
- callbackUrl = "your_callback_url",
- accountReference = "CompanyName"
- )
-
-darajaPaymentResponse.onSuccess { paymentResponse ->
+val paymentResponse: DarajaResult = daraja.mpesaExpress(
+ businessShortCode = "174379",
+ amount = 1,
+ phoneNumber = "07xxxxxxxx", // or +2547xxxxxxxx or 2547xxxxxxxx
+ transactionDesc = "M-Pesa payment",
+ callbackUrl = "your_callback_url",
+ accountReference = "CompanyName"
+)
+
+paymentResponse.onSuccess { paymentResponse ->
println(paymentResponse)
}.onFailure { error ->
- println(error)
+ println(error)
}
```
@@ -87,16 +97,37 @@ darajaPaymentResponse.onSuccess { paymentResponse ->
- To check the status of M-Pesa Express(Lipa na M-Pesa Online) STK request, invoke the `mpesaExpressQuery` function:
```Kotlin
-val darajaMpesaExpressQuery: DarajaResult = daraja.mpesaExpressQuery(
- businessShortCode = "174379",
- timeStamp = "20160216165627",
- checkOutRequestID = "ws_CO_260520211133524545"
- )
+val mpesaExpressQuery: DarajaResult = daraja.mpesaExpressQuery(
+ businessShortCode = "174379",
+ timeStamp = "20160216165627",
+ checkOutRequestID = "ws_CO_260520211133524545"
+)
-darajaMpesaExpressQuery.onSuccess { mpesaExpressQuery ->
+mpesaExpressQuery.onSuccess { mpesaExpressQuery ->
println(mpesaExpressQuery)
}.onFailure { error ->
- println(error)
+ println(error)
+}
+```
+
+### Generate Dynamic QR Code
+
+- To generate a dynamic QR code that can be used to trigger payment, invoke the `generateQR` function:
+
+```kotlin
+val qrCode: DarajaResult = daraja.generateDynamicQr(
+ merchantName = "Shop 1",
+ referenceNumber = UUID().uuidString,
+ amount = 10,
+ transactionCode = DarajaTransactionCode.sm,
+ cpi = "373132",
+ size = 300
+)
+
+qrCode.onSuccess { qr ->
+ println(qr)
+}.onFailure { error ->
+ println(error)
}
```
diff --git a/docs/swift.md b/docs/swift.md
index cf3d7be2..aa277012 100644
--- a/docs/swift.md
+++ b/docs/swift.md
@@ -1 +1,122 @@
-# Swift
\ No newline at end of file
+# __Swift SDK__
+
+## Getting Started
+
+To get started with Daraja Multiplatform SDK, you will need
+to [create a Daraja API account](https://developer.safaricom.co.ke/) on the Daraja API portal
+and [set up a new test application](https://developer.safaricom.co.ke/MyApps).
+
+Once you have access to the created test app, retrieve the ___Consumer Key___, ___Consumer Secret___ and ___Passkey___.
+
+## Installation
+
+- In Xcode add the DarajaMultiplatform package, navigate to File -> Add package dependecies. Enter the package GitHub
+ url below, select the package and choose the target(s) to add it to and click "Add Package".
+
+```curl
+https://github.com/VictorKabata/DarajaSwiftPackage.git
+```
+
+> To protect your sensitive API keys, it's recommended to store your Consumer Key, Consumer Secret, and Passkey in your
+> project's environment secrets (outside of version control). This ensures they are not accidentally exposed in public
+> repositories.
+
+- Instantiate a `Daraja` object, providing the necessary environment variables. This Daraja instance serves as the entry
+ point for various M-Pesa operations. Core functionalities include obtaining an access token required for subsequent
+ API calls and initiating M-Pesa Express STK push requests.
+
+```swift
+let daraja = Daraja(
+ consumerKey: "your_consumer_key",
+ consumerSecret: "your_consumer_secret",
+ passKey: "your_pass_key",
+ environment: DarajaEnvironment.sandboxEnvironment)
+```
+
+- The environment can be either _DarajaEnvironment.sandboxEnvironment_ or _DarajaEnvironment.productionEnvironment_.
+
+> Daraja Multiplatform includes built-in network logging, which is active by default in sandbox mode but disabled in
+> production mode. To inspect network requests and responses, view logs in Android Studio's Logcat under the __Daraja
+Multiplatform__ tag.
+
+## Usage
+
+- Start by importing the package to your Swift code:
+
+```swift
+import DarajaMultiplatform
+```
+
+### Request Access Token
+
+To request an access token from Daraja API, invoke the `authorization` function:
+
+```swift
+daraja.authorization()
+.onSuccess(action: { accessToken in
+ print(accessToken)
+})
+.onFailure(action: { error in
+ print(error)
+})
+
+```
+
+### Initiate M-Pesa Express STK Request
+
+- To initiate M-Pesa Express(Lipa na M-Pesa Online) STK request, invoke the `mpesaExpress` function:
+
+```swift
+daraja.mpesaExpress(
+ businessShortCode: "174379",
+ amount: 1,
+ phoneNumber: "07xxxxxxxx", // or +2547xxxxxxxx or 2547xxxxxxxx
+ transactionType: .customerBuyGoodsOnline,
+ transactionDesc: "your_callback_url",
+ callbackUrl: "your_callback_url",
+ accountReference: "CompanyName"
+).onSuccess(action: { paymentResponse in
+ print(paymentResponse)
+})
+.onFailure(action: { error in
+ print(error)
+})
+
+```
+
+### Query M-Pesa Express STK Status
+
+- To check the status of M-Pesa Express(Lipa na M-Pesa Online) STK request, invoke the `mpesaExpressQuery` function:
+
+```swift
+daraja.mpesaExpressQuery(
+ businessShortCode: "174379",
+ timestamp: "20160216165627",
+ checkoutRequestID: "ws_CO_260520211133524545"
+).onSuccess(action: { transaction in
+ print(transaction)
+})
+.onFailure(action: { error in
+ print(error)
+})
+```
+
+### Generate Dynamic QR Code
+
+- To generate a dynamic QR code that can be used to trigger payment, invoke the `generateQR` function:
+
+```swift
+daraja.generateDynamicQr(
+ merchantName: "Shop 1",
+ referenceNumber: UUID().uuidString,
+ amount: 10,
+ transactionCode: DarajaTransactionCode.sm,
+ cpi: "373132",
+ size: 300
+).onSuccess(action: { qrCode in
+ print(qrCode)
+})
+.onFailure(action: { error in
+ print(error)
+})
+```
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 1b8236cd..e8128c77 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -16,4 +16,6 @@ kotlin.mpp.androidSourceSetLayoutVersion1.nowarn=true
org.gradle.caching=true
android.defaults.buildfeatures.buildconfig=true
-android.nonFinalResIds=false
\ No newline at end of file
+android.nonFinalResIds=false
+
+kotlin.apple.xcodeCompatibility.nowarn=true
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index dfa1a965..5f690430 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -6,7 +6,7 @@ detekt = "1.23.6"
spotless = "6.2.2"
dokka = "1.9.20"
kover = "0.8.3"
-mulitplatformSwiftPackage = "2.0.3"
+mulitplatformSwiftPackage = "2.2.2"
gradleVersionUpdate = "0.51.0"
# Kotlin Multiplatform Version
@@ -33,7 +33,7 @@ jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" }
kotlinX-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" }
kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" }
-multiplatformSwiftPackage = { id = "com.chromaticnoise.multiplatform-swiftpackage", version.ref = "mulitplatformSwiftPackage" }
+multiplatformSwiftPackage = { id = "io.github.luca992.multiplatform-swiftpackage", version.ref = "mulitplatformSwiftPackage" }
gradleVersionUpdate = { id = "com.github.ben-manes.versions", version.ref = "gradleVersionUpdate" }
compose = { id = "org.jetbrains.compose", version.ref = "composeMultiplatform" }
diff --git a/mkdocs.yml b/mkdocs.yml
index d3aa1c01..46997bb0 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -11,7 +11,7 @@ remote_branch: gh-pages
nav:
- Overview: index.md
- Kotlin SDK: kotlin.md
-# - Swift SDK: swift.md
+ - Swift SDK: swift.md
theme:
name: material
diff --git a/samples/android/app/build.gradle.kts b/samples/android/app/build.gradle.kts
index da0710ac..08cf1ff6 100644
--- a/samples/android/app/build.gradle.kts
+++ b/samples/android/app/build.gradle.kts
@@ -1,8 +1,7 @@
-import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties
-
plugins {
alias(libs.plugins.android.application)
alias(libs.plugins.jetbrains.kotlin.android)
+ alias(libs.plugins.kotlinx.serialization)
}
android {
@@ -75,6 +74,8 @@ dependencies {
implementation("io.github.victorkabata:daraja-multiplatform:0.9.8")
+ implementation(libs.kotlinx.serialization)
+
testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
diff --git a/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/components/CollapsableCard.kt b/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/components/CollapsableCard.kt
index 0008843e..f8eb0b17 100644
--- a/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/components/CollapsableCard.kt
+++ b/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/components/CollapsableCard.kt
@@ -1,28 +1,41 @@
+@file:OptIn(ExperimentalFoundationApi::class)
+
package com.vickbt.daraja.android.ui.components
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
+import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.clickable
+import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.pager.HorizontalPager
+import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.rounded.KeyboardArrowRight
import androidx.compose.material3.Card
+import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Tab
+import androidx.compose.material3.TabRow
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.rotate
+import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
@@ -33,8 +46,19 @@ import androidx.compose.ui.unit.sp
fun CollapsableCard(
modifier: Modifier = Modifier,
cardTitle: String,
- cardContent: @Composable () -> Unit
+ tabItems: List = listOf("Request", "Response"),
+ requestContent: @Composable () -> Unit = {},
+ responseContent: @Composable () -> Unit = {}
) {
+ var selectedTabIndex by remember { mutableIntStateOf(0) }
+ val pagerState = rememberPagerState { tabItems.size }
+
+ LaunchedEffect(selectedTabIndex) {
+ pagerState.animateScrollToPage(selectedTabIndex)
+ }
+ LaunchedEffect(pagerState.currentPage, pagerState.isScrollInProgress) {
+ selectedTabIndex = pagerState.currentPage
+ }
var isExpanded by remember { mutableStateOf(false) }
val rotationDegree by animateFloatAsState(
@@ -44,18 +68,23 @@ fun CollapsableCard(
Card(
modifier = modifier
+ .clickable(onClick = { isExpanded = !isExpanded },
+ indication = null,
+ interactionSource = remember { MutableInteractionSource() })
.fillMaxWidth()
- .padding(8.dp)
- .clickable { isExpanded = !isExpanded },
- shape = RoundedCornerShape(8.dp)
+ .padding(vertical = 8.dp),
+ shape = RoundedCornerShape(8.dp),
) {
Column(
- modifier = Modifier.padding(16.dp),
+ modifier = Modifier.padding(vertical = 16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
+ //region Title and Drop Down Icon
Row(
- modifier = Modifier.fillMaxWidth(),
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(horizontal = 16.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
@@ -73,10 +102,52 @@ fun CollapsableCard(
contentDescription = null
)
}
+ //endregion
+ //region
AnimatedVisibility(visible = isExpanded) {
- cardContent()
+ Column(modifier = Modifier) {
+ TabRow(
+ modifier = Modifier.fillMaxWidth(),
+ selectedTabIndex = selectedTabIndex,
+ containerColor = Color.Transparent,
+ contentColor = MaterialTheme.colorScheme.onSurface,
+ divider = {
+ HorizontalDivider(
+ thickness = 1.dp,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ }
+ ) {
+ tabItems.forEachIndexed { index, title ->
+ Tab(
+ selected = index == selectedTabIndex,
+ onClick = { selectedTabIndex = index },
+ text = {
+ Text(
+ text = title,
+ fontWeight = FontWeight.Normal,
+ fontSize = 16.sp,
+ maxLines = 1,
+ overflow = TextOverflow.Ellipsis
+ )
+ }
+ )
+ }
+ }
+
+ HorizontalPager(
+ modifier = Modifier.padding(16.dp),
+ state = pagerState
+ ) { page ->
+ when (page) {
+ 0 -> requestContent()
+ 1 -> responseContent()
+ }
+ }
+ }
}
+ //endregion
}
}
@@ -84,10 +155,7 @@ fun CollapsableCard(
}
@Composable
-@Preview
+@Preview(showBackground = true)
fun CollapsableCardPreview() {
- CollapsableCard(cardTitle = "Title") {
- Text(text = "Content")
- }
-
+ CollapsableCard(cardTitle = "Title", requestContent = {}, responseContent = {})
}
\ No newline at end of file
diff --git a/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/components/ResultComponent.kt b/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/components/ResultComponent.kt
new file mode 100644
index 00000000..cabc094b
--- /dev/null
+++ b/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/components/ResultComponent.kt
@@ -0,0 +1,59 @@
+package com.vickbt.daraja.android.ui.components
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.rounded.AddCircle
+import androidx.compose.material3.Card
+import androidx.compose.material3.CardDefaults
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButton
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.text.font.FontWeight
+import androidx.compose.ui.text.style.TextAlign
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+
+@Composable
+fun ResultComponent(modifier: Modifier = Modifier, result: String, onClickCopy: (String) -> Unit) {
+ Card(
+ modifier = Modifier,
+ shape = RoundedCornerShape(2.dp),
+ colors = CardDefaults.cardColors(MaterialTheme.colorScheme.surface.copy(alpha = .6f))
+ ) {
+ Column(modifier = modifier) {
+ Box(modifier = Modifier.fillMaxWidth()) {
+ IconButton(
+ modifier = Modifier
+ .size(48.dp)
+ .align(Alignment.TopEnd),
+ onClick = { onClickCopy(result) }) {
+ Icon(
+ imageVector = Icons.Rounded.AddCircle,
+ contentDescription = "Copy",
+ tint = MaterialTheme.colorScheme.onSurface
+ )
+ }
+ }
+
+ Text(
+ modifier = Modifier.padding(8.dp),
+ text = result,
+ fontWeight = FontWeight.Normal,
+ fontSize = 18.sp,
+ overflow = TextOverflow.Ellipsis,
+ textAlign = TextAlign.Start,
+ color = MaterialTheme.colorScheme.onSurface
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/screen/MainScreen.kt b/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/screen/MainScreen.kt
index 1ac36089..f28653ba 100644
--- a/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/screen/MainScreen.kt
+++ b/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/screen/MainScreen.kt
@@ -1,32 +1,80 @@
package com.vickbt.daraja.android.ui.screen
-import androidx.compose.foundation.layout.Column
+import android.util.Log
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.vickbt.daraja.android.ui.components.CollapsableCard
+import com.vickbt.daraja.android.ui.components.ResultComponent
+import com.vickbt.daraja.android.utils.toJson
import com.vickbt.darajakmp.Daraja
import org.koin.compose.koinInject
@Composable
fun MainScreen(modifier: Modifier = Modifier, daraja: Daraja = koinInject()) {
- Column(modifier = modifier.padding(horizontal = 12.dp)) {
- CollapsableCard(cardTitle = "M-Pesa Express") {
- MpesaExpressScreen(modifier = Modifier, daraja = daraja)
+ LazyColumn(modifier = modifier.padding(horizontal = 12.dp)) {
+ item {
+ var requestContent by remember { mutableStateOf("") }
+ Log.e("VicKbt", "Result: ${requestContent.toJson()}")
+ CollapsableCard(
+ cardTitle = "M-Pesa Express",
+ requestContent = {
+ MpesaExpressScreen(
+ modifier = Modifier,
+ daraja = daraja,
+ onResult = { requestContent = it.toJson() })
+ },
+ responseContent = {
+ ResultComponent(
+ modifier = Modifier,
+ result = requestContent.toJson(),
+ onClickCopy = {}
+ )
+ }
+ )
}
- CollapsableCard(cardTitle = "Dynamic QR") {
- QrCodeScreen(modifier = Modifier, daraja = daraja)
+ item {
+ var requestContent by remember { mutableStateOf("") }
+ CollapsableCard(
+ cardTitle = "Dynamic QR",
+ requestContent = {
+ QrCodeScreen(
+ modifier = Modifier,
+ daraja = daraja,
+ onResult = { requestContent = it.toJson() })
+ },
+ responseContent = {
+ ResultComponent(
+ modifier = Modifier,
+ result = requestContent.toJson(),
+ onClickCopy = {}
+ )
+ }
+ )
}
- CollapsableCard(cardTitle = "C2B Registration") {
- C2BScreen(modifier = Modifier, daraja = daraja)
+ item {
+ CollapsableCard(
+ cardTitle = "C2B Registration",
+ requestContent = { C2BScreen(modifier = Modifier, daraja = daraja) },
+ responseContent = {}
+ )
}
- CollapsableCard(cardTitle = "Initiate C2B") {
- C2BInitiateScreen(modifier = Modifier, daraja = daraja)
+ item {
+ CollapsableCard(
+ cardTitle = "Initiate C2B",
+ requestContent = { C2BInitiateScreen(modifier = Modifier, daraja = daraja) },
+ responseContent = {}
+ )
}
}
}
diff --git a/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/screen/MpesaExpressScreen.kt b/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/screen/MpesaExpressScreen.kt
index 03471a07..08b32dde 100644
--- a/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/screen/MpesaExpressScreen.kt
+++ b/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/screen/MpesaExpressScreen.kt
@@ -38,13 +38,14 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.vickbt.darajakmp.Daraja
+import com.vickbt.darajakmp.network.models.MpesaExpressResponse
import com.vickbt.darajakmp.utils.DarajaTransactionType
import com.vickbt.darajakmp.utils.onFailure
import com.vickbt.darajakmp.utils.onSuccess
import org.koin.compose.koinInject
@Composable
-fun MpesaExpressScreen(modifier: Modifier = Modifier, daraja: Daraja) {
+fun MpesaExpressScreen(modifier: Modifier = Modifier, daraja: Daraja, onResult: (MpesaExpressResponse) -> Unit = {}) {
val context = LocalContext.current
@@ -115,7 +116,7 @@ fun MpesaExpressScreen(modifier: Modifier = Modifier, daraja: Daraja) {
callbackUrl = "https://mydomain.com",
accountReference = "CompanyX"
).onSuccess {
- Toast.makeText(context, "Success: $it", Toast.LENGTH_SHORT).show()
+ onResult(it)
}.onFailure {
Toast.makeText(context, "Error: ${it.errorMessage}", Toast.LENGTH_SHORT).show()
}
diff --git a/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/screen/QrCodeScreen.kt b/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/screen/QrCodeScreen.kt
index 09660fe1..f535e680 100644
--- a/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/screen/QrCodeScreen.kt
+++ b/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/screen/QrCodeScreen.kt
@@ -37,13 +37,14 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.vickbt.darajakmp.Daraja
+import com.vickbt.darajakmp.network.models.DynamicQrResponse
import com.vickbt.darajakmp.utils.DarajaTransactionCode
import com.vickbt.darajakmp.utils.onFailure
import com.vickbt.darajakmp.utils.onSuccess
import java.util.UUID
@Composable
-fun QrCodeScreen(modifier: Modifier, daraja: Daraja) {
+fun QrCodeScreen(modifier: Modifier, daraja: Daraja, onResult: (DynamicQrResponse) -> Unit = {}) {
val context = LocalContext.current
@@ -130,7 +131,7 @@ fun QrCodeScreen(modifier: Modifier, daraja: Daraja) {
transactionCode = DarajaTransactionCode.PB,
size = 300
).onSuccess {
- Toast.makeText(context, "Success: $it", Toast.LENGTH_SHORT).show()
+ onResult(it)
isLoading = false
}.onFailure {
Toast.makeText(context, "Error: ${it.errorMessage}", Toast.LENGTH_SHORT)
diff --git a/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/theme/Theme.kt b/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/theme/Theme.kt
index 654e7371..2a67f709 100644
--- a/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/theme/Theme.kt
+++ b/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/theme/Theme.kt
@@ -35,7 +35,5 @@ fun DarajaAndroidTheme(
else -> LightColorScheme
}
- MaterialTheme(
- colorScheme = colorScheme, typography = Typography, content = content
- )
+ MaterialTheme(colorScheme = colorScheme, content = content)
}
\ No newline at end of file
diff --git a/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/theme/Type.kt b/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/theme/Type.kt
deleted file mode 100644
index 3b1e1e63..00000000
--- a/samples/android/app/src/main/java/com/vickbt/daraja/android/ui/theme/Type.kt
+++ /dev/null
@@ -1,34 +0,0 @@
-package com.vickbt.daraja.android.ui.theme
-
-import androidx.compose.material3.Typography
-import androidx.compose.ui.text.TextStyle
-import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.sp
-
-// Set of Material typography styles to start with
-val Typography = Typography(
- bodyLarge = TextStyle(
- fontFamily = FontFamily.Default,
- fontWeight = FontWeight.Normal,
- fontSize = 16.sp,
- lineHeight = 24.sp,
- letterSpacing = 0.5.sp
- )
- /* Other default text styles to override
- titleLarge = TextStyle(
- fontFamily = FontFamily.Default,
- fontWeight = FontWeight.Normal,
- fontSize = 22.sp,
- lineHeight = 28.sp,
- letterSpacing = 0.sp
- ),
- labelSmall = TextStyle(
- fontFamily = FontFamily.Default,
- fontWeight = FontWeight.Medium,
- fontSize = 11.sp,
- lineHeight = 16.sp,
- letterSpacing = 0.5.sp
- )
- */
-)
\ No newline at end of file
diff --git a/samples/android/app/src/main/java/com/vickbt/daraja/android/utils/Extensions.kt b/samples/android/app/src/main/java/com/vickbt/daraja/android/utils/Extensions.kt
new file mode 100644
index 00000000..3ec745dd
--- /dev/null
+++ b/samples/android/app/src/main/java/com/vickbt/daraja/android/utils/Extensions.kt
@@ -0,0 +1,12 @@
+package com.vickbt.daraja.android.utils
+
+import kotlinx.serialization.encodeToString
+import kotlinx.serialization.json.Json
+
+inline fun T.toJson(): String {
+ val json = Json {
+ prettyPrint = true
+ }
+
+ return json.encodeToString(this).replaceFirst("\"","")
+}
\ No newline at end of file
diff --git a/samples/android/gradle/libs.versions.toml b/samples/android/gradle/libs.versions.toml
index eddd3b74..b65591af 100644
--- a/samples/android/gradle/libs.versions.toml
+++ b/samples/android/gradle/libs.versions.toml
@@ -2,6 +2,8 @@
agp = "8.5.2"
kotlin = "1.9.0"
coreKtx = "1.13.1"
+serialization="1.9.0"
+serializationJson ="1.7.3"
junit = "4.13.2"
junitVersion = "1.2.1"
espressoCore = "3.6.1"
@@ -25,6 +27,7 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
+kotlinx-serialization={module="org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref= "serializationJson" }
koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "koinBom" }
koin-android = { module = "io.insert-koin:koin-androidx-compose" }
@@ -32,4 +35,5 @@ koin-android = { module = "io.insert-koin:koin-androidx-compose" }
[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
jetbrains-kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
+kotlinx-serialization={id="org.jetbrains.kotlin.plugin.serialization", version.ref="serialization"}
diff --git a/app-iOS/app-iOS.xcodeproj/project.pbxproj b/samples/ios/Daraja iOS.xcodeproj/project.pbxproj
similarity index 53%
rename from app-iOS/app-iOS.xcodeproj/project.pbxproj
rename to samples/ios/Daraja iOS.xcodeproj/project.pbxproj
index 267b2056..260f48b8 100644
--- a/app-iOS/app-iOS.xcodeproj/project.pbxproj
+++ b/samples/ios/Daraja iOS.xcodeproj/project.pbxproj
@@ -3,136 +3,117 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 56;
+ objectVersion = 60;
objects = {
/* Begin PBXBuildFile section */
- 1C89232D2AA7C1EF00700D4F /* DarajaMultiplatform in Frameworks */ = {isa = PBXBuildFile; productRef = 1C89232C2AA7C1EF00700D4F /* DarajaMultiplatform */; };
- 1CDEAB762A8BC12A00EBC42E /* app_iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CDEAB752A8BC12A00EBC42E /* app_iOSApp.swift */; };
- 1CDEAB782A8BC12A00EBC42E /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CDEAB772A8BC12A00EBC42E /* ContentView.swift */; };
- 1CDEAB7A2A8BC12C00EBC42E /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1CDEAB792A8BC12C00EBC42E /* Assets.xcassets */; };
- 1CDEAB7D2A8BC12C00EBC42E /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1CDEAB7C2A8BC12C00EBC42E /* Preview Assets.xcassets */; };
- 2F22CD940E774E4F0F3FFB25 /* Pods_app_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6B2DEC6E2423A8E7DC28CEC6 /* Pods_app_iOS.framework */; };
+ 1CC3931E2CDCE7FE0092A633 /* DarajaMultiplatform in Frameworks */ = {isa = PBXBuildFile; productRef = 1CC3931D2CDCE7FE0092A633 /* DarajaMultiplatform */; };
+ 1CC393212CDCF2DD0092A633 /* DarajaMultiplatform in Frameworks */ = {isa = PBXBuildFile; productRef = 1CC393202CDCF2DD0092A633 /* DarajaMultiplatform */; };
+ 1CC393242CDCF7C40092A633 /* DarajaMultiplatform in Frameworks */ = {isa = PBXBuildFile; productRef = 1CC393232CDCF7C40092A633 /* DarajaMultiplatform */; };
+ 1CC4C39E2C7204EC00D66DB1 /* Daraja_iOSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC4C39D2C7204EC00D66DB1 /* Daraja_iOSApp.swift */; };
+ 1CC4C3A02C7204EC00D66DB1 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CC4C39F2C7204EC00D66DB1 /* ContentView.swift */; };
+ 1CC4C3A22C7204EE00D66DB1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1CC4C3A12C7204EE00D66DB1 /* Assets.xcassets */; };
+ 1CC4C3A52C7204EE00D66DB1 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1CC4C3A42C7204EE00D66DB1 /* Preview Assets.xcassets */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
- 1CDEAB722A8BC12A00EBC42E /* app-iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "app-iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
- 1CDEAB752A8BC12A00EBC42E /* app_iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = app_iOSApp.swift; sourceTree = ""; };
- 1CDEAB772A8BC12A00EBC42E /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
- 1CDEAB792A8BC12C00EBC42E /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
- 1CDEAB7C2A8BC12C00EBC42E /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
- 6B2DEC6E2423A8E7DC28CEC6 /* Pods_app_iOS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_app_iOS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
- 93C28A294DB1FFBA3DF573C6 /* Pods-app-iOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app-iOS.release.xcconfig"; path = "Target Support Files/Pods-app-iOS/Pods-app-iOS.release.xcconfig"; sourceTree = ""; };
- 965FE27CCADC2E0C3CD864CC /* Pods-app-iOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-app-iOS.debug.xcconfig"; path = "Target Support Files/Pods-app-iOS/Pods-app-iOS.debug.xcconfig"; sourceTree = ""; };
+ 1CC4C39A2C7204EC00D66DB1 /* Daraja iOS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Daraja iOS.app"; sourceTree = BUILT_PRODUCTS_DIR; };
+ 1CC4C39D2C7204EC00D66DB1 /* Daraja_iOSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Daraja_iOSApp.swift; sourceTree = ""; };
+ 1CC4C39F2C7204EC00D66DB1 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; };
+ 1CC4C3A12C7204EE00D66DB1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 1CC4C3A42C7204EE00D66DB1 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
- 1CDEAB6F2A8BC12A00EBC42E /* Frameworks */ = {
+ 1CC4C3972C7204EC00D66DB1 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 1C89232D2AA7C1EF00700D4F /* DarajaMultiplatform in Frameworks */,
- 2F22CD940E774E4F0F3FFB25 /* Pods_app_iOS.framework in Frameworks */,
+ 1CC393212CDCF2DD0092A633 /* DarajaMultiplatform in Frameworks */,
+ 1CC3931E2CDCE7FE0092A633 /* DarajaMultiplatform in Frameworks */,
+ 1CC393242CDCF7C40092A633 /* DarajaMultiplatform in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
- 18EE2D64E07D047770CDEB83 /* Pods */ = {
+ 1CC4C3912C7204EC00D66DB1 = {
isa = PBXGroup;
children = (
- 965FE27CCADC2E0C3CD864CC /* Pods-app-iOS.debug.xcconfig */,
- 93C28A294DB1FFBA3DF573C6 /* Pods-app-iOS.release.xcconfig */,
+ 1CC4C39C2C7204EC00D66DB1 /* Daraja iOS */,
+ 1CC4C39B2C7204EC00D66DB1 /* Products */,
);
- path = Pods;
sourceTree = "";
};
- 1CDEAB692A8BC12A00EBC42E = {
+ 1CC4C39B2C7204EC00D66DB1 /* Products */ = {
isa = PBXGroup;
children = (
- 1CDEAB742A8BC12A00EBC42E /* app-iOS */,
- 1CDEAB732A8BC12A00EBC42E /* Products */,
- 18EE2D64E07D047770CDEB83 /* Pods */,
- CAA5BE13CB8DBB302143230F /* Frameworks */,
- );
- sourceTree = "";
- };
- 1CDEAB732A8BC12A00EBC42E /* Products */ = {
- isa = PBXGroup;
- children = (
- 1CDEAB722A8BC12A00EBC42E /* app-iOS.app */,
+ 1CC4C39A2C7204EC00D66DB1 /* Daraja iOS.app */,
);
name = Products;
sourceTree = "";
};
- 1CDEAB742A8BC12A00EBC42E /* app-iOS */ = {
+ 1CC4C39C2C7204EC00D66DB1 /* Daraja iOS */ = {
isa = PBXGroup;
children = (
- 1CDEAB752A8BC12A00EBC42E /* app_iOSApp.swift */,
- 1CDEAB772A8BC12A00EBC42E /* ContentView.swift */,
- 1CDEAB792A8BC12C00EBC42E /* Assets.xcassets */,
- 1CDEAB7B2A8BC12C00EBC42E /* Preview Content */,
+ 1CC4C39D2C7204EC00D66DB1 /* Daraja_iOSApp.swift */,
+ 1CC4C39F2C7204EC00D66DB1 /* ContentView.swift */,
+ 1CC4C3A12C7204EE00D66DB1 /* Assets.xcassets */,
+ 1CC4C3A32C7204EE00D66DB1 /* Preview Content */,
);
- path = "app-iOS";
+ path = "Daraja iOS";
sourceTree = "";
};
- 1CDEAB7B2A8BC12C00EBC42E /* Preview Content */ = {
+ 1CC4C3A32C7204EE00D66DB1 /* Preview Content */ = {
isa = PBXGroup;
children = (
- 1CDEAB7C2A8BC12C00EBC42E /* Preview Assets.xcassets */,
+ 1CC4C3A42C7204EE00D66DB1 /* Preview Assets.xcassets */,
);
path = "Preview Content";
sourceTree = "";
};
- CAA5BE13CB8DBB302143230F /* Frameworks */ = {
- isa = PBXGroup;
- children = (
- 6B2DEC6E2423A8E7DC28CEC6 /* Pods_app_iOS.framework */,
- );
- name = Frameworks;
- sourceTree = "";
- };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
- 1CDEAB712A8BC12A00EBC42E /* app-iOS */ = {
+ 1CC4C3992C7204EC00D66DB1 /* Daraja iOS */ = {
isa = PBXNativeTarget;
- buildConfigurationList = 1CDEAB802A8BC12C00EBC42E /* Build configuration list for PBXNativeTarget "app-iOS" */;
+ buildConfigurationList = 1CC4C3A82C7204EE00D66DB1 /* Build configuration list for PBXNativeTarget "Daraja iOS" */;
buildPhases = (
- 753367D962DB398356D0B725 /* [CP] Check Pods Manifest.lock */,
- 1CDEAB6E2A8BC12A00EBC42E /* Sources */,
- 1CDEAB6F2A8BC12A00EBC42E /* Frameworks */,
- 1CDEAB702A8BC12A00EBC42E /* Resources */,
+ 1CC4C3962C7204EC00D66DB1 /* Sources */,
+ 1CC4C3972C7204EC00D66DB1 /* Frameworks */,
+ 1CC4C3982C7204EC00D66DB1 /* Resources */,
);
buildRules = (
);
dependencies = (
);
- name = "app-iOS";
+ name = "Daraja iOS";
packageProductDependencies = (
- 1C89232C2AA7C1EF00700D4F /* DarajaMultiplatform */,
+ 1CC3931D2CDCE7FE0092A633 /* DarajaMultiplatform */,
+ 1CC393202CDCF2DD0092A633 /* DarajaMultiplatform */,
+ 1CC393232CDCF7C40092A633 /* DarajaMultiplatform */,
);
- productName = "app-iOS";
- productReference = 1CDEAB722A8BC12A00EBC42E /* app-iOS.app */;
+ productName = "Daraja iOS";
+ productReference = 1CC4C39A2C7204EC00D66DB1 /* Daraja iOS.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
- 1CDEAB6A2A8BC12A00EBC42E /* Project object */ = {
+ 1CC4C3922C7204EC00D66DB1 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = 1;
- LastSwiftUpdateCheck = 1430;
- LastUpgradeCheck = 1430;
+ LastSwiftUpdateCheck = 1540;
+ LastUpgradeCheck = 1540;
TargetAttributes = {
- 1CDEAB712A8BC12A00EBC42E = {
- CreatedOnToolsVersion = 14.3.1;
+ 1CC4C3992C7204EC00D66DB1 = {
+ CreatedOnToolsVersion = 15.4;
};
};
};
- buildConfigurationList = 1CDEAB6D2A8BC12A00EBC42E /* Build configuration list for PBXProject "app-iOS" */;
+ buildConfigurationList = 1CC4C3952C7204EC00D66DB1 /* Build configuration list for PBXProject "Daraja iOS" */;
compatibilityVersion = "Xcode 14.0";
developmentRegion = en;
hasScannedForEncodings = 0;
@@ -140,73 +121,49 @@
en,
Base,
);
- mainGroup = 1CDEAB692A8BC12A00EBC42E;
+ mainGroup = 1CC4C3912C7204EC00D66DB1;
packageReferences = (
- 1C89232B2AA7C1EF00700D4F /* XCRemoteSwiftPackageReference "DarajaSwiftPackage" */,
+ 1CC393222CDCF7C40092A633 /* XCLocalSwiftPackageReference "../../daraja/swiftpackage" */,
);
- productRefGroup = 1CDEAB732A8BC12A00EBC42E /* Products */;
+ productRefGroup = 1CC4C39B2C7204EC00D66DB1 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
- 1CDEAB712A8BC12A00EBC42E /* app-iOS */,
+ 1CC4C3992C7204EC00D66DB1 /* Daraja iOS */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
- 1CDEAB702A8BC12A00EBC42E /* Resources */ = {
+ 1CC4C3982C7204EC00D66DB1 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 1CDEAB7D2A8BC12C00EBC42E /* Preview Assets.xcassets in Resources */,
- 1CDEAB7A2A8BC12C00EBC42E /* Assets.xcassets in Resources */,
+ 1CC4C3A52C7204EE00D66DB1 /* Preview Assets.xcassets in Resources */,
+ 1CC4C3A22C7204EE00D66DB1 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
-/* Begin PBXShellScriptBuildPhase section */
- 753367D962DB398356D0B725 /* [CP] Check Pods Manifest.lock */ = {
- isa = PBXShellScriptBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- inputFileListPaths = (
- );
- inputPaths = (
- "${PODS_PODFILE_DIR_PATH}/Podfile.lock",
- "${PODS_ROOT}/Manifest.lock",
- );
- name = "[CP] Check Pods Manifest.lock";
- outputFileListPaths = (
- );
- outputPaths = (
- "$(DERIVED_FILE_DIR)/Pods-app-iOS-checkManifestLockResult.txt",
- );
- runOnlyForDeploymentPostprocessing = 0;
- shellPath = /bin/sh;
- shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
- showEnvVarsInLog = 0;
- };
-/* End PBXShellScriptBuildPhase section */
-
/* Begin PBXSourcesBuildPhase section */
- 1CDEAB6E2A8BC12A00EBC42E /* Sources */ = {
+ 1CC4C3962C7204EC00D66DB1 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 1CDEAB782A8BC12A00EBC42E /* ContentView.swift in Sources */,
- 1CDEAB762A8BC12A00EBC42E /* app_iOSApp.swift in Sources */,
+ 1CC4C3A02C7204EC00D66DB1 /* ContentView.swift in Sources */,
+ 1CC4C39E2C7204EC00D66DB1 /* Daraja_iOSApp.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
- 1CDEAB7E2A8BC12C00EBC42E /* Debug */ = {
+ 1CC4C3A62C7204EE00D66DB1 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
@@ -239,7 +196,8 @@
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
- GCC_C_LANGUAGE_STANDARD = gnu11;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
@@ -253,20 +211,22 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 16.4;
+ IPHONEOS_DEPLOYMENT_TARGET = 17.5;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
- SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
- 1CDEAB7F2A8BC12C00EBC42E /* Release */ = {
+ 1CC4C3A72C7204EE00D66DB1 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
@@ -299,7 +259,8 @@
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
- GCC_C_LANGUAGE_STANDARD = gnu11;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
@@ -307,28 +268,26 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 16.4;
+ IPHONEOS_DEPLOYMENT_TARGET = 17.5;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
- SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
- 1CDEAB812A8BC12C00EBC42E /* Debug */ = {
+ 1CC4C3A92C7204EE00D66DB1 /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 965FE27CCADC2E0C3CD864CC /* Pods-app-iOS.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_ASSET_PATHS = "\"app-iOS/Preview Content\"";
+ DEVELOPMENT_ASSET_PATHS = "\"Daraja iOS/Preview Content\"";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_KEY_CFBundleDisplayName = "Daraja Multiplatform iOS";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
@@ -339,7 +298,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = "VicKbt.app-iOS";
+ PRODUCT_BUNDLE_IDENTIFIER = "VicKbt.Daraja-iOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
@@ -347,18 +306,16 @@
};
name = Debug;
};
- 1CDEAB822A8BC12C00EBC42E /* Release */ = {
+ 1CC4C3AA2C7204EE00D66DB1 /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 93C28A294DB1FFBA3DF573C6 /* Pods-app-iOS.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
- DEVELOPMENT_ASSET_PATHS = "\"app-iOS/Preview Content\"";
+ DEVELOPMENT_ASSET_PATHS = "\"Daraja iOS/Preview Content\"";
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
- INFOPLIST_KEY_CFBundleDisplayName = "Daraja Multiplatform iOS";
INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES;
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
INFOPLIST_KEY_UILaunchScreen_Generation = YES;
@@ -369,7 +326,7 @@
"@executable_path/Frameworks",
);
MARKETING_VERSION = 1.0;
- PRODUCT_BUNDLE_IDENTIFIER = "VicKbt.app-iOS";
+ PRODUCT_BUNDLE_IDENTIFIER = "VicKbt.Daraja-iOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
@@ -380,44 +337,47 @@
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
- 1CDEAB6D2A8BC12A00EBC42E /* Build configuration list for PBXProject "app-iOS" */ = {
+ 1CC4C3952C7204EC00D66DB1 /* Build configuration list for PBXProject "Daraja iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- 1CDEAB7E2A8BC12C00EBC42E /* Debug */,
- 1CDEAB7F2A8BC12C00EBC42E /* Release */,
+ 1CC4C3A62C7204EE00D66DB1 /* Debug */,
+ 1CC4C3A72C7204EE00D66DB1 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
- 1CDEAB802A8BC12C00EBC42E /* Build configuration list for PBXNativeTarget "app-iOS" */ = {
+ 1CC4C3A82C7204EE00D66DB1 /* Build configuration list for PBXNativeTarget "Daraja iOS" */ = {
isa = XCConfigurationList;
buildConfigurations = (
- 1CDEAB812A8BC12C00EBC42E /* Debug */,
- 1CDEAB822A8BC12C00EBC42E /* Release */,
+ 1CC4C3A92C7204EE00D66DB1 /* Debug */,
+ 1CC4C3AA2C7204EE00D66DB1 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
-/* Begin XCRemoteSwiftPackageReference section */
- 1C89232B2AA7C1EF00700D4F /* XCRemoteSwiftPackageReference "DarajaSwiftPackage" */ = {
- isa = XCRemoteSwiftPackageReference;
- repositoryURL = "https://github.com/VictorKabata/DarajaSwiftPackage.git";
- requirement = {
- kind = upToNextMajorVersion;
- minimumVersion = 0.0.1;
- };
+/* Begin XCLocalSwiftPackageReference section */
+ 1CC393222CDCF7C40092A633 /* XCLocalSwiftPackageReference "../../daraja/swiftpackage" */ = {
+ isa = XCLocalSwiftPackageReference;
+ relativePath = ../../daraja/swiftpackage;
};
-/* End XCRemoteSwiftPackageReference section */
+/* End XCLocalSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
- 1C89232C2AA7C1EF00700D4F /* DarajaMultiplatform */ = {
+ 1CC3931D2CDCE7FE0092A633 /* DarajaMultiplatform */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = DarajaMultiplatform;
+ };
+ 1CC393202CDCF2DD0092A633 /* DarajaMultiplatform */ = {
+ isa = XCSwiftPackageProductDependency;
+ productName = DarajaMultiplatform;
+ };
+ 1CC393232CDCF7C40092A633 /* DarajaMultiplatform */ = {
isa = XCSwiftPackageProductDependency;
- package = 1C89232B2AA7C1EF00700D4F /* XCRemoteSwiftPackageReference "DarajaSwiftPackage" */;
productName = DarajaMultiplatform;
};
/* End XCSwiftPackageProductDependency section */
};
- rootObject = 1CDEAB6A2A8BC12A00EBC42E /* Project object */;
+ rootObject = 1CC4C3922C7204EC00D66DB1 /* Project object */;
}
diff --git a/app-iOS/app-iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/samples/ios/Daraja iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata
similarity index 100%
rename from app-iOS/app-iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata
rename to samples/ios/Daraja iOS.xcodeproj/project.xcworkspace/contents.xcworkspacedata
diff --git a/app-iOS/app-iOS/Assets.xcassets/AccentColor.colorset/Contents.json b/samples/ios/Daraja iOS/Assets.xcassets/AccentColor.colorset/Contents.json
similarity index 100%
rename from app-iOS/app-iOS/Assets.xcassets/AccentColor.colorset/Contents.json
rename to samples/ios/Daraja iOS/Assets.xcassets/AccentColor.colorset/Contents.json
diff --git a/app-iOS/app-iOS/Assets.xcassets/AppIcon.appiconset/Contents.json b/samples/ios/Daraja iOS/Assets.xcassets/AppIcon.appiconset/Contents.json
similarity index 100%
rename from app-iOS/app-iOS/Assets.xcassets/AppIcon.appiconset/Contents.json
rename to samples/ios/Daraja iOS/Assets.xcassets/AppIcon.appiconset/Contents.json
diff --git a/app-iOS/app-iOS/Assets.xcassets/Contents.json b/samples/ios/Daraja iOS/Assets.xcassets/Contents.json
similarity index 100%
rename from app-iOS/app-iOS/Assets.xcassets/Contents.json
rename to samples/ios/Daraja iOS/Assets.xcassets/Contents.json
diff --git a/samples/ios/Daraja iOS/ContentView.swift b/samples/ios/Daraja iOS/ContentView.swift
new file mode 100644
index 00000000..cb82b82f
--- /dev/null
+++ b/samples/ios/Daraja iOS/ContentView.swift
@@ -0,0 +1,73 @@
+//
+// ContentView.swift
+// Daraja iOS
+//
+// Created by Victor Kabata on 18/08/2024.
+//
+
+import SwiftUI
+import DarajaMultiplatform
+
+struct ContentView: View {
+ var body: some View {
+
+// let daraja=Daraja(consumerKey: "ewP4be7L00bA8RylBT0z9tEhlgkMlLJiLV0gJB374BeGnyJ7", consumerSecret: "o2fNGnTmYfHAfl65HAaK9jLh2a703wkTgiz1dqGCO9Vi3yBCOBL5Rpuu13kIgrQm", passKey: "bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919", environment: DarajaEnvironment.sandboxEnvironment)
+
+ List {
+ DisclosureGroup("M-Pesa Express") {
+ @State var amount: Int32 = 1
+ @FocusState var isAmountTextFieldFocused: Bool
+
+ @State var phoneNumber: String = ""
+ @FocusState var isPhoneTextFieldFocused: Bool
+
+ VStack {
+ // Amount textfield
+ TextField("Amount", text: .init(get: { "\(amount)" }, set: {
+ if let newValue = Int32($0) {
+ amount = newValue
+ }
+ }))
+ .padding()
+ .accentColor(.green)
+ .background(.white)
+ .keyboardType(.numberPad)
+ .overlay(
+ RoundedRectangle(cornerRadius: 10)
+ .stroke(isAmountTextFieldFocused ? Color.green : Color.gray.opacity(0.5), lineWidth: 1)
+ )
+ .cornerRadius(10)
+ .shadow(color: Color.gray.opacity(0.4), radius: 4, x: 0, y: 2)
+ .focused($isAmountTextFieldFocused)
+
+ // Phone Number textfield
+ TextField("Phone Number", text: $phoneNumber)
+ .padding()
+ .accentColor(.green)
+ .background(.white)
+ .keyboardType(.phonePad)
+ .overlay(
+ RoundedRectangle(cornerRadius: 10)
+ .stroke(isPhoneTextFieldFocused ? Color.green : Color.gray.opacity(0.5), lineWidth: 1)
+ )
+ .cornerRadius(10)
+ .shadow(color: Color.gray.opacity(0.4), radius: 4, x: 0, y: 2)
+ .focused($isPhoneTextFieldFocused)
+
+ // Pay Button
+ Button(action: {}) {
+ Image(systemName: "plus")
+ .padding(20)
+ .background(Color.green)
+ .foregroundColor(.white)
+ .clipShape(Circle())
+ }
+ }
+ }
+ }
+ }
+}
+
+#Preview {
+ ContentView()
+}
diff --git a/app-iOS/app-iOS/app_iOSApp.swift b/samples/ios/Daraja iOS/Daraja_iOSApp.swift
similarity index 52%
rename from app-iOS/app-iOS/app_iOSApp.swift
rename to samples/ios/Daraja iOS/Daraja_iOSApp.swift
index bbeedd73..dcf488a4 100644
--- a/app-iOS/app-iOS/app_iOSApp.swift
+++ b/samples/ios/Daraja iOS/Daraja_iOSApp.swift
@@ -1,14 +1,14 @@
//
-// app_iOSApp.swift
-// app-iOS
+// Daraja_iOSApp.swift
+// Daraja iOS
//
-// Created by Victor Kabata on 15/08/2023.
+// Created by Victor Kabata on 18/08/2024.
//
import SwiftUI
@main
-struct app_iOSApp: App {
+struct Daraja_iOSApp: App {
var body: some Scene {
WindowGroup {
ContentView()
diff --git a/samples/ios/Daraja iOS/MpesaExpressView.swift b/samples/ios/Daraja iOS/MpesaExpressView.swift
new file mode 100644
index 00000000..5822e057
--- /dev/null
+++ b/samples/ios/Daraja iOS/MpesaExpressView.swift
@@ -0,0 +1,8 @@
+//
+// MpesaExpressView.swift
+// Daraja iOS
+//
+// Created by Victor Kabata on 18/08/2024.
+//
+
+import Foundation
diff --git a/app-iOS/app-iOS/Preview Content/Preview Assets.xcassets/Contents.json b/samples/ios/Daraja iOS/Preview Content/Preview Assets.xcassets/Contents.json
similarity index 100%
rename from app-iOS/app-iOS/Preview Content/Preview Assets.xcassets/Contents.json
rename to samples/ios/Daraja iOS/Preview Content/Preview Assets.xcassets/Contents.json