Merge pull request #21 from hmalik144/replace_api

This commit is contained in:
2023-02-13 18:14:24 +00:00
committed by GitHub
16 changed files with 154 additions and 369 deletions

View File

@@ -21,6 +21,11 @@ if (flutterVersionName == null) {
flutterVersionName = '1.0' flutterVersionName = '1.0'
} }
def relStorePassword = System.getenv("storePassword")
def relKeyPassword = System.getenv("keyPassword")
def relKeyAlias = System.getenv("keyAlias")
def relStoreFile = System.getenv("storeFile")
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
@@ -43,7 +48,6 @@ android {
} }
defaultConfig { defaultConfig {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.appttude.h_mal.easycc" applicationId "com.appttude.h_mal.easycc"
// You can update the following values to match your application needs. // You can update the following values to match your application needs.
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-build-configuration.
@@ -53,11 +57,22 @@ android {
versionName flutterVersionName versionName flutterVersionName
} }
signingConfigs {
release {
storePassword relStorePassword
keyPassword relKeyPassword
keyAlias relKeyAlias
storeFile file(relStoreFile)
}
}
buildTypes { buildTypes {
release { release {
// TODO: Add your own signing config for the release build. signingConfig signingConfigs.release
// Signing with the debug keys for now, so `flutter run --release` works. minifyEnabled true
signingConfig signingConfigs.debug shrinkResources true
useProguard true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
} }
} }
} }

View File

@@ -1,57 +1,73 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.appttude.h_mal.easycc"> package="com.appttude.h_mal.easycc">
<application
android:label="easycc" <uses-permission android:name="android.permission.INTERNET" />
<application
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/launcher_icon"> android:icon="@mipmap/launcher_icon"
android:label="easycc">
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:exported="true" android:exported="true"
android:hardwareAccelerated="true"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@style/LaunchTheme" android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as <!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. --> to determine the Window background behind the Flutter UI. -->
<meta-data <meta-data
android:name="io.flutter.embedding.android.NormalTheme" android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" android:resource="@style/NormalTheme" />
/>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="es.antonborri.home_widget.action.LAUNCH" />
</intent-filter>
</activity>
<activity
android:name="com.appttude.h_mal.easycc.CurrencyAppWidgetConfigureActivity"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
<intent-filter>
<action android:name="es.antonborri.home_widget.action.LAUNCH" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="com.appttude.h_mal.easycc.CurrencyAppWidgetConfigureActivity"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
<!-- Home Widget -->
<receiver
android:name="AppWidgetProvider"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/currency_app_widget_info" />
</receiver>
<receiver
android:name="es.antonborri.home_widget.HomeWidgetBackgroundReceiver"
android:exported="true">
<intent-filter>
<action android:name="es.antonborri.home_widget.action.BACKGROUND" />
</intent-filter>
</receiver>
<!-- Don't delete the meta-data below. <service
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java --> android:name="es.antonborri.home_widget.HomeWidgetBackgroundService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />
<!-- Home Widget -->
<!-- Home Widget --> <!-- Don't delete the meta-data below.
<receiver android:name="AppWidgetProvider" android:exported="true"> This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/currency_app_widget_info" />
</receiver>
<receiver android:name="es.antonborri.home_widget.HomeWidgetBackgroundReceiver" android:exported="true">
<intent-filter>
<action android:name="es.antonborri.home_widget.action.BACKGROUND" />
</intent-filter>
</receiver>
<service android:name="es.antonborri.home_widget.HomeWidgetBackgroundService"
android:permission="android.permission.BIND_JOB_SERVICE" android:exported="true"/>
<!-- Home Widget -->
<meta-data <meta-data
android:name="flutterEmbedding" android:name="flutterEmbedding"
android:value="2" /> android:value="2" />

View File

@@ -1,20 +1,17 @@
package com.appttude.h_mal.easycc package com.appttude.h_mal.easycc
import android.appwidget.AppWidgetManager import android.appwidget.AppWidgetManager
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.Uri import android.net.Uri
import android.widget.RemoteViews import android.widget.RemoteViews
import android.widget.Toast import android.widget.Toast
import es.antonborri.home_widget.HomeWidgetBackgroundIntent import es.antonborri.home_widget.HomeWidgetBackgroundIntent
import es.antonborri.home_widget.HomeWidgetLaunchIntent import es.antonborri.home_widget.HomeWidgetLaunchIntent
import es.antonborri.home_widget.HomeWidgetPlugin
import es.antonborri.home_widget.HomeWidgetProvider import es.antonborri.home_widget.HomeWidgetProvider
class AppWidgetProvider : HomeWidgetProvider(){ class AppWidgetProvider : HomeWidgetProvider() {
override fun onUpdate( override fun onUpdate(
context: Context, context: Context,
appWidgetManager: AppWidgetManager, appWidgetManager: AppWidgetManager,
@@ -23,54 +20,46 @@ class AppWidgetProvider : HomeWidgetProvider(){
) { ) {
appWidgetIds.forEach { widgetId -> appWidgetIds.forEach { widgetId ->
val views = RemoteViews(context.packageName, R.layout.currency_app_widget).apply { val views = RemoteViews(context.packageName, R.layout.currency_app_widget).apply {
// Data from background operation received val uri = createUpdateUri(widgetId)
val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast(context, uri)
// checks if forced update or period update
val forcedUpdate: Boolean =
widgetData.getBoolean("${widgetId}_forced_update", false)
if (!forcedUpdate) {
widgetData.edit().putBoolean("${widgetId}_forced_update", true).apply()
backgroundIntent.send()
return@apply
}
val from: String? = widgetData.getString("${widgetId}_from", null) val from: String? = widgetData.getString("${widgetId}_from", null)
val to: String? = widgetData.getString("${widgetId}_to", null) val to: String? = widgetData.getString("${widgetId}_to", null)
val rate: String? = widgetData.getString("${widgetId}_rate", null) val rate: String? = widgetData.getString("${widgetId}_rate", null)
if (from.isNullOrBlank() or to.isNullOrBlank() or rate.isNullOrBlank()) { if (from.isNullOrBlank() or to.isNullOrBlank() or rate.isNullOrBlank()) {
Toast.makeText(context, "Unable to review data for widget", Toast.LENGTH_SHORT).show() Toast.makeText(context, "Unable to review data for widget", Toast.LENGTH_SHORT)
.show()
return@apply return@apply
} }
val titleString = "${from}${to}" val titleString = "${from}${to}"
setTextViewText(R.id.exchangeName, titleString) setTextViewText(R.id.exchangeName, titleString)
setTextViewText(R.id.exchangeRate, rate.toString()) setTextViewText(R.id.exchangeRate, rate.toString())
val uri = Uri.parse("myAppWidget://updatewidget").buildUpon()
.appendQueryParameter("id", widgetId.toString())
.build()
setImageViewResource(R.id.refresh_icon, R.drawable.ic_refresh_white_24dp) setImageViewResource(R.id.refresh_icon, R.drawable.ic_refresh_white_24dp)
val backgroundIntent = HomeWidgetBackgroundIntent.getBroadcast(context, uri)
setOnClickPendingIntent(R.id.refresh_icon, backgroundIntent) setOnClickPendingIntent(R.id.refresh_icon, backgroundIntent)
val pendingIntent = HomeWidgetLaunchIntent.getActivity(context, val pendingIntent = HomeWidgetLaunchIntent.getActivity(
MainActivity::class.java) context,
MainActivity::class.java
)
widgetData.edit().putBoolean("${widgetId}_forced_update", false).apply()
setOnClickPendingIntent(R.id.widget_view, pendingIntent) setOnClickPendingIntent(R.id.widget_view, pendingIntent)
} }
appWidgetManager.updateAppWidget(widgetId, views) appWidgetManager.updateAppWidget(widgetId, views)
} }
} }
override fun onReceive(context: Context?, intent: Intent?) {
super.onReceive(context, intent)
when (intent?.action) {
}
val appWidgetManager = AppWidgetManager.getInstance(context);
val appWidgetIds = appWidgetManager.getAppWidgetIds(
context?.let { ComponentName(it, this::class.java) })
val widgetDate = context?.let { HomeWidgetPlugin.getData(it) }
appWidgetIds.forEach { widgetId ->
}
}
override fun onDeleted(context: Context?, appWidgetIds: IntArray?) { override fun onDeleted(context: Context?, appWidgetIds: IntArray?) {
super.onDeleted(context, appWidgetIds) super.onDeleted(context, appWidgetIds)
@@ -85,4 +74,11 @@ class AppWidgetProvider : HomeWidgetProvider(){
} }
} }
} }
// Send update broadcast to widget app class
private fun createUpdateUri(widgetId: Int): Uri? {
return Uri.parse("myAppWidget://updatewidget").buildUpon()
.appendQueryParameter("id", widgetId.toString())
.build()
}
} }

View File

@@ -2,160 +2,43 @@
<resources> <resources>
<string-array name="currency_arrays"> <string-array name="currency_arrays">
<item>ALL - Albanian Lek</item>
<item>AFN - Afghan Afghani</item>
<item>DZD - Algerian Dinar</item> <item>DZD - Algerian Dinar</item>
<item>AOA - Angolan Kwanza</item>
<item>ARS - Argentine Peso</item> <item>ARS - Argentine Peso</item>
<item>AMD - Armenian Dram</item>
<item>AWG - Aruban Florin</item>
<item>AUD - Australian Dollar</item> <item>AUD - Australian Dollar</item>
<item>AZN - Azerbaijani Manat</item>
<item>BSD - Bahamian Dollar</item>
<item>BHD - Bahraini Dinar</item>
<item>BDT - Bangladeshi Taka</item>
<item>BBD - Barbadian Dollar</item>
<item>BYR - Belarusian Ruble</item>
<item>BZD - Belize Dollar</item>
<item>BTN - Bhutanese Ngultrum</item>
<item>BTC - Bitcoin</item> <item>BTC - Bitcoin</item>
<item>BOB - Bolivian Boliviano</item>
<item>BAM - Bosnia And Herzegovina Konvertibilna Marka</item>
<item>BWP - Botswana Pula</item>
<item>BRL - Brazilian Real</item> <item>BRL - Brazilian Real</item>
<item>GBP - British Pound</item> <item>GBP - British Pound</item>
<item>BND - Brunei Dollar</item>
<item>BGN - Bulgarian Lev</item> <item>BGN - Bulgarian Lev</item>
<item>BIF - Burundi Franc</item>
<item>KHR - Cambodian Riel</item>
<item>CAD - Canadian Dollar</item> <item>CAD - Canadian Dollar</item>
<item>CVE - Cape Verdean Escudo</item>
<item>KYD - Cayman Islands Dollar</item>
<item>XAF - Central African CFA Franc</item>
<item>XPF - CFP Franc</item>
<item>CLP - Chilean Peso</item>
<item>CNY - Chinese Yuan</item> <item>CNY - Chinese Yuan</item>
<item>COP - Colombian Peso</item>
<item>KMF - Comorian Franc</item>
<item>CDF - Congolese Franc</item>
<item>CRC - Costa Rican Colon</item>
<item>HRK - Croatian Kuna</item> <item>HRK - Croatian Kuna</item>
<item>CUP - Cuban Peso</item>
<item>CZK - Czech Koruna</item> <item>CZK - Czech Koruna</item>
<item>DKK - Danish Krone</item> <item>DKK - Danish Krone</item>
<item>DJF - Djiboutian Franc</item>
<item>DOP - Dominican Peso</item>
<item>XCD - East Caribbean Dollar</item>
<item>EGP - Egyptian Pound</item>
<item>ERN - Eritrean Nakfa</item>
<item>ETB - Ethiopian Birr</item>
<item>EUR - Euro</item> <item>EUR - Euro</item>
<item>FKP - Falkland Islands Pound</item>
<item>FJD - Fijian Dollar</item>
<item>GMD - Gambian Dalasi</item>
<item>GEL - Georgian Lari</item>
<item>GHS - Ghanaian Cedi</item>
<item>GIP - Gibraltar Pound</item>
<item>GTQ - Guatemalan Quetzal</item>
<item>GNF - Guinean Franc</item>
<item>GYD - Guyanese Dollar</item>
<item>HTG - Haitian Gourde</item>
<item>HNL - Honduran Lempira</item>
<item>HKD - Hong Kong Dollar</item> <item>HKD - Hong Kong Dollar</item>
<item>HUF - Hungarian Forint</item> <item>HUF - Hungarian Forint</item>
<item>ISK - Icelandic Kr\u00f3na</item> <item>ISK - Icelandic Kr\u00f3na</item>
<item>INR - Indian Rupee</item> <item>INR - Indian Rupee</item>
<item>IDR - Indonesian Rupiah</item> <item>IDR - Indonesian Rupiah</item>
<item>IRR - Iranian Rial</item>
<item>IQD - Iraqi Dinar</item>
<item>ILS - Israeli New Sheqel</item> <item>ILS - Israeli New Sheqel</item>
<item>JMD - Jamaican Dollar</item>
<item>JPY - Japanese Yen</item> <item>JPY - Japanese Yen</item>
<item>JOD - Jordanian Dinar</item>
<item>KZT - Kazakhstani Tenge</item>
<item>KES - Kenyan Shilling</item>
<item>KWD - Kuwaiti Dinar</item>
<item>KGS - Kyrgyzstani Som</item>
<item>LAK - Lao Kip</item>
<item>LVL - Latvian Lats</item>
<item>LBP - Lebanese Lira</item>
<item>LSL - Lesotho Loti</item>
<item>LRD - Liberian Dollar</item>
<item>LYD - Libyan Dinar</item>
<item>MOP - Macanese Pataca</item>
<item>MKD - Macedonian Denar</item>
<item>MGA - Malagasy Ariary</item>
<item>MWK - Malawian Kwacha</item>
<item>MYR - Malaysian Ringgit</item> <item>MYR - Malaysian Ringgit</item>
<item>MVR - Maldivian Rufiyaa</item>
<item>MRO - Mauritanian Ouguiya</item>
<item>MUR - Mauritian Rupee</item>
<item>MXN - Mexican Peso</item> <item>MXN - Mexican Peso</item>
<item>MDL - Moldovan Leu</item>
<item>MNT - Mongolian Tugrik</item>
<item>MAD - Moroccan Dirham</item> <item>MAD - Moroccan Dirham</item>
<item>MZN - Mozambican Metical</item>
<item>MMK - Myanma Kyat</item>
<item>NAD - Namibian Dollar</item>
<item>NPR - Nepalese Rupee</item>
<item>ANG - Netherlands Antillean Gulden</item>
<item>TWD - New Taiwan Dollar</item> <item>TWD - New Taiwan Dollar</item>
<item>NZD - New Zealand Dollar</item> <item>NZD - New Zealand Dollar</item>
<item>NIO - Nicaraguan Cordoba</item>
<item>NGN - Nigerian Naira</item>
<item>KPW - North Korean Won</item>
<item>NOK - Norwegian Krone</item> <item>NOK - Norwegian Krone</item>
<item>OMR - Omani Rial</item>
<item>TOP - Paanga</item>
<item>PKR - Pakistani Rupee</item>
<item>PAB - Panamanian Balboa</item>
<item>PGK - Papua New Guinean Kina</item>
<item>PYG - Paraguayan Guarani</item>
<item>PEN - Peruvian Nuevo Sol</item>
<item>PHP - Philippine Peso</item> <item>PHP - Philippine Peso</item>
<item>PLN - Polish Zloty</item> <item>PLN - Polish Zloty</item>
<item>QAR - Qatari Riyal</item>
<item>RON - Romanian Leu</item> <item>RON - Romanian Leu</item>
<item>RUB - Russian Ruble</item> <item>RUB - Russian Ruble</item>
<item>RWF - Rwandan Franc</item>
<item>SHP - Saint Helena Pound</item>
<item>WST - Samoan Tala</item>
<item>STD - Sao Tome And Principe Dobra</item>
<item>SAR - Saudi Riyal</item>
<item>RSD - Serbian Dinar</item>
<item>SCR - Seychellois Rupee</item>
<item>SLL - Sierra Leonean Leone</item>
<item>SGD - Singapore Dollar</item> <item>SGD - Singapore Dollar</item>
<item>SBD - Solomon Islands Dollar</item>
<item>SOS - Somali Shilling</item>
<item>ZAR - South African Rand</item> <item>ZAR - South African Rand</item>
<item>KRW - South Korean Won</item> <item>KRW - South Korean Won</item>
<item>XDR - Special Drawing Rights</item>
<item>LKR - Sri Lankan Rupee</item>
<item>SDG - Sudanese Pound</item>
<item>SRD - Surinamese Dollar</item>
<item>SZL - Swazi Lilangeni</item>
<item>SEK - Swedish Krona</item> <item>SEK - Swedish Krona</item>
<item>CHF - Swiss Franc</item> <item>CHF - Swiss Franc</item>
<item>SYP - Syrian Pound</item>
<item>TJS - Tajikistani Somoni</item>
<item>TZS - Tanzanian Shilling</item>
<item>THB - Thai Baht</item> <item>THB - Thai Baht</item>
<item>TTD - Trinidad and Tobago Dollar</item>
<item>TND - Tunisian Dinar</item>
<item>TRY - Turkish New Lira</item> <item>TRY - Turkish New Lira</item>
<item>TMT - Turkmenistan Manat</item> <item>USD - US Dollar</item>
<item>AED - UAE Dirham</item>
<item>UGX - Ugandan Shilling</item>
<item>UAH - Ukrainian Hryvnia</item>
<item>USD - United States Dollar</item>
<item>UYU - Uruguayan Peso</item>
<item>UZS - Uzbekistani Som</item>
<item>VUV - Vanuatu Vatu</item>
<item>VEF - Venezuelan Bolivar</item>
<item>VND - Vietnamese Dong</item>
<item>XOF - West African CFA Franc</item>
<item>YER - Yemeni Rial</item>
<item>ZMW - Zambian Kwacha</item>
</string-array> </string-array>
</resources> </resources>

View File

@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:configure="com.appttude.h_mal.easycc.CurrencyAppWidgetConfigureActivity" android:configure="com.appttude.h_mal.easycc.CurrencyAppWidgetConfigureActivity"
android:initialKeyguardLayout="@layout/currency_app_widget" android:initialKeyguardLayout="@layout/currency_app_widget"
android:initialLayout="@layout/currency_app_widget" android:initialLayout="@layout/currency_app_widget"
@@ -7,5 +8,6 @@
android:minHeight="40dp" android:minHeight="40dp"
android:previewImage="@drawable/easyycc_widget_preview" android:previewImage="@drawable/easyycc_widget_preview"
android:resizeMode="horizontal|vertical" android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="3600000" android:updatePeriodMillis="14400000"
android:widgetCategory="home_screen|keyguard" /> android:widgetCategory="home_screen|keyguard"
tools:targetApi="jelly_bean_mr1" />

View File

@@ -9,159 +9,42 @@ const Color colourFive = Color(0xFFC6E0FF);
const double paddingGlobal = 12; const double paddingGlobal = 12;
final List<String> listOfCurrencies = <String>[ final List<String> listOfCurrencies = <String>[
'ALL - Albanian Lek',
'AFN - Afghan Afghani',
'DZD - Algerian Dinar', 'DZD - Algerian Dinar',
'AOA - Angolan Kwanza',
'ARS - Argentine Peso', 'ARS - Argentine Peso',
'AMD - Armenian Dram',
'AWG - Aruban Florin',
'AUD - Australian Dollar', 'AUD - Australian Dollar',
'AZN - Azerbaijani Manat',
'BSD - Bahamian Dollar',
'BHD - Bahraini Dinar',
'BDT - Bangladeshi Taka',
'BBD - Barbadian Dollar',
'BYR - Belarusian Ruble',
'BZD - Belize Dollar',
'BTN - Bhutanese Ngultrum',
'BTC - Bitcoin', 'BTC - Bitcoin',
'BOB - Bolivian Boliviano',
'BAM - Bosnia And Herzegovina Konvertibilna Marka',
'BWP - Botswana Pula',
'BRL - Brazilian Real', 'BRL - Brazilian Real',
'GBP - British Pound', 'GBP - British Pound',
'BND - Brunei Dollar',
'BGN - Bulgarian Lev', 'BGN - Bulgarian Lev',
'BIF - Burundi Franc',
'KHR - Cambodian Riel',
'CAD - Canadian Dollar', 'CAD - Canadian Dollar',
'CVE - Cape Verdean Escudo',
'KYD - Cayman Islands Dollar',
'XAF - Central African CFA Franc',
'XPF - CFP Franc',
'CLP - Chilean Peso',
'CNY - Chinese Yuan', 'CNY - Chinese Yuan',
'COP - Colombian Peso',
'KMF - Comorian Franc',
'CDF - Congolese Franc',
'CRC - Costa Rican Colon',
'HRK - Croatian Kuna', 'HRK - Croatian Kuna',
'CUP - Cuban Peso',
'CZK - Czech Koruna', 'CZK - Czech Koruna',
'DKK - Danish Krone', 'DKK - Danish Krone',
'DJF - Djiboutian Franc',
'DOP - Dominican Peso',
'XCD - East Caribbean Dollar',
'EGP - Egyptian Pound',
'ERN - Eritrean Nakfa',
'ETB - Ethiopian Birr',
'EUR - Euro', 'EUR - Euro',
'FKP - Falkland Islands Pound',
'FJD - Fijian Dollar',
'GMD - Gambian Dalasi',
'GEL - Georgian Lari',
'GHS - Ghanaian Cedi',
'GIP - Gibraltar Pound',
'GTQ - Guatemalan Quetzal',
'GNF - Guinean Franc',
'GYD - Guyanese Dollar',
'HTG - Haitian Gourde',
'HNL - Honduran Lempira',
'HKD - Hong Kong Dollar', 'HKD - Hong Kong Dollar',
'HUF - Hungarian Forint', 'HUF - Hungarian Forint',
'ISK - Icelandic Kr\u00f3na', 'ISK - Icelandic Kr\u00f3na',
'INR - Indian Rupee', 'INR - Indian Rupee',
'IDR - Indonesian Rupiah', 'IDR - Indonesian Rupiah',
'IRR - Iranian Rial',
'IQD - Iraqi Dinar',
'ILS - Israeli New Sheqel', 'ILS - Israeli New Sheqel',
'JMD - Jamaican Dollar',
'JPY - Japanese Yen', 'JPY - Japanese Yen',
'JOD - Jordanian Dinar',
'KZT - Kazakhstani Tenge',
'KES - Kenyan Shilling',
'KWD - Kuwaiti Dinar',
'KGS - Kyrgyzstani Som',
'LAK - Lao Kip',
'LVL - Latvian Lats',
'LBP - Lebanese Lira',
'LSL - Lesotho Loti',
'LRD - Liberian Dollar',
'LYD - Libyan Dinar',
'MOP - Macanese Pataca',
'MKD - Macedonian Denar',
'MGA - Malagasy Ariary',
'MWK - Malawian Kwacha',
'MYR - Malaysian Ringgit', 'MYR - Malaysian Ringgit',
'MVR - Maldivian Rufiyaa',
'MRO - Mauritanian Ouguiya',
'MUR - Mauritian Rupee',
'MXN - Mexican Peso', 'MXN - Mexican Peso',
'MDL - Moldovan Leu',
'MNT - Mongolian Tugrik',
'MAD - Moroccan Dirham', 'MAD - Moroccan Dirham',
'MZN - Mozambican Metical',
'MMK - Myanma Kyat',
'NAD - Namibian Dollar',
'NPR - Nepalese Rupee',
'ANG - Netherlands Antillean Gulden',
'TWD - New Taiwan Dollar', 'TWD - New Taiwan Dollar',
'NZD - New Zealand Dollar', 'NZD - New Zealand Dollar',
'NIO - Nicaraguan Cordoba',
'NGN - Nigerian Naira',
'KPW - North Korean Won',
'NOK - Norwegian Krone', 'NOK - Norwegian Krone',
'OMR - Omani Rial',
'TOP - Paanga',
'PKR - Pakistani Rupee',
'PAB - Panamanian Balboa',
'PGK - Papua New Guinean Kina',
'PYG - Paraguayan Guarani',
'PEN - Peruvian Nuevo Sol',
'PHP - Philippine Peso', 'PHP - Philippine Peso',
'PLN - Polish Zloty', 'PLN - Polish Zloty',
'QAR - Qatari Riyal',
'RON - Romanian Leu', 'RON - Romanian Leu',
'RUB - Russian Ruble', 'RUB - Russian Ruble',
'RWF - Rwandan Franc',
'SHP - Saint Helena Pound',
'WST - Samoan Tala',
'STD - Sao Tome And Principe Dobra',
'SAR - Saudi Riyal',
'RSD - Serbian Dinar',
'SCR - Seychellois Rupee',
'SLL - Sierra Leonean Leone',
'SGD - Singapore Dollar', 'SGD - Singapore Dollar',
'SBD - Solomon Islands Dollar',
'SOS - Somali Shilling',
'ZAR - South African Rand', 'ZAR - South African Rand',
'KRW - South Korean Won', 'KRW - South Korean Won',
'XDR - Special Drawing Rights',
'LKR - Sri Lankan Rupee',
'SDG - Sudanese Pound',
'SRD - Surinamese Dollar',
'SZL - Swazi Lilangeni',
'SEK - Swedish Krona', 'SEK - Swedish Krona',
'CHF - Swiss Franc', 'CHF - Swiss Franc',
'SYP - Syrian Pound',
'TJS - Tajikistani Somoni',
'TZS - Tanzanian Shilling',
'THB - Thai Baht', 'THB - Thai Baht',
'TTD - Trinidad and Tobago Dollar',
'TND - Tunisian Dinar',
'TRY - Turkish New Lira', 'TRY - Turkish New Lira',
'TMT - Turkmenistan Manat', 'USD - US Dollar'
'AED - UAE Dirham',
'UGX - Ugandan Shilling',
'UAH - Ukrainian Hryvnia',
'USD - United States Dollar',
'UYU - Uruguayan Peso',
'UZS - Uzbekistani Som',
'VUV - Vanuatu Vatu',
'VEF - Venezuelan Bolivar',
'VND - Vietnamese Dong',
'XOF - West African CFA Franc',
'YER - Yemeni Rial',
'ZMW - Zambian Kwacha'
]; ];

View File

@@ -1,4 +1,5 @@
// ignore: depend_on_referenced_packages // ignore_for_file: non_constant_identifier_names, depend_on_referenced_packages
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:easy_cc_flutter/data/network/app_dio.dart'; import 'package:easy_cc_flutter/data/network/app_dio.dart';
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
@@ -8,57 +9,52 @@ import '../model/currency.dart';
part 'currency_api.g.dart'; part 'currency_api.g.dart';
@RestApi(baseUrl: "https://free.currencyconverterapi.com/api/v3/") @RestApi(baseUrl: "https://exchange-rates.abstractapi.com/v1/")
abstract class CurrencyApi { abstract class CurrencyApi {
factory CurrencyApi(Dio dio, {String baseUrl}) = _CurrencyApi; factory CurrencyApi(Dio dio, {String baseUrl}) = _CurrencyApi;
static const api = String.fromEnvironment('currencyApiKey'); static const api = String.fromEnvironment('currencyApiKey');
static CurrencyApi create() { static CurrencyApi create() {
final dio = AppDio.createDio(); final dio = AppDio.createDio();
dio.options.queryParameters.addAll({"apiKey": api}); dio.options.queryParameters.addAll({"api_key": api});
return _CurrencyApi(dio); return _CurrencyApi(dio);
} }
@GET("/convert?") @GET("/live?")
Future<HttpResponse<ResponseObject>> getConversion(@Query("q") String currency); Future<HttpResponse<ResponseObject>> getConversion(
@Query("base") String from, @Query("target") String to);
} }
@JsonSerializable() @JsonSerializable()
class ResponseObject implements CurrencyMapper{ class ResponseObject implements CurrencyMapper {
dynamic query; String base;
Map<String, CurrencyObject>? results; int last_updated;
Map<String, double>? exchange_rates;
ResponseObject({ ResponseObject(this.base, this.last_updated, this.exchange_rates);
this.query,
this.results
});
factory ResponseObject.fromJson(Map<String, dynamic> json) => _$ResponseObjectFromJson(json); factory ResponseObject.fromJson(Map<String, dynamic> json) =>
_$ResponseObjectFromJson(json);
Map<String, dynamic> toJson() => _$ResponseObjectToJson(this); Map<String, dynamic> toJson() => _$ResponseObjectToJson(this);
@override @override
Currency convert() { Currency convert() {
CurrencyObject? cur = results?.entries.elementAt(0).value; return Currency(base, exchange_rates?.keys.first, exchange_rates?.values.first);
return Currency(cur?.fr, cur?.to, cur?.val);
} }
} }
@JsonSerializable() @JsonSerializable()
class CurrencyObject{ class CurrencyObject {
String? id; String? id;
String? fr; String? fr;
String? to; String? to;
double? val; double? val;
CurrencyObject({ CurrencyObject({this.id, this.fr, this.to, this.val});
this.id,
this.fr,
this.to,
this.val
});
factory CurrencyObject.fromJson(Map<String, dynamic> json) => _$CurrencyObjectFromJson(json); factory CurrencyObject.fromJson(Map<String, dynamic> json) =>
_$CurrencyObjectFromJson(json);
Map<String, dynamic> toJson() => _$CurrencyObjectToJson(this); Map<String, dynamic> toJson() => _$CurrencyObjectToJson(this);
} }

View File

@@ -15,14 +15,14 @@ mixin SafeApiCall {
Map<String, dynamic>? errorResponse = dioError.response?.data?["error"]; Map<String, dynamic>? errorResponse = dioError.response?.data?["error"];
String error; String error;
if (errorResponse?["error"] != null){ if (errorResponse?["message"] != null){
error = errorResponse!["error"]; error = errorResponse!["message"];
} else if (dioError.error != null){ } else if (dioError.message.isNotEmpty){
error = dioError.error; error = dioError.message;
} else { } else {
error = "Failed to retrieve data from api"; error = "Failed to retrieve data from api";
} }
logger.e(dioError.error); logger.e(error);
throw HttpException(error); throw HttpException(error);
} }

View File

@@ -33,10 +33,8 @@ class RepositoryImpl extends Repository with SafeApiCall {
String from = fromCurrency.getCurrencyCode(); String from = fromCurrency.getCurrencyCode();
String to = toCurrency.getCurrencyCode(); String to = toCurrency.getCurrencyCode();
String currency = "${from}_$to";
try { try {
ResponseObject responseObject = await getDataFromApiCall(_api.getConversion(currency)); ResponseObject responseObject = await getDataFromApiCall(_api.getConversion(from, to));
return responseObject.convert(); return responseObject.convert();
} on HttpException catch(error) { } on HttpException catch(error) {
logger.e(error); logger.e(error);

View File

@@ -3,6 +3,7 @@ import 'package:easy_cc_flutter/data/network/currency_api.dart';
import 'package:easy_cc_flutter/data/repository/repository_impl.dart'; import 'package:easy_cc_flutter/data/repository/repository_impl.dart';
import 'package:easy_cc_flutter/main_view_model.dart'; import 'package:easy_cc_flutter/main_view_model.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
import 'data/prefs/preference_provider.dart'; import 'data/prefs/preference_provider.dart';
import 'data/repository/repository.dart'; import 'data/repository/repository.dart';

View File

@@ -62,6 +62,7 @@ Future<void> updateWidget(String? widgetId, Repository repository) async {
await HomeWidget.saveWidgetData<String>("${widgetId}_from", from); await HomeWidget.saveWidgetData<String>("${widgetId}_from", from);
await HomeWidget.saveWidgetData<String>("${widgetId}_to", to); await HomeWidget.saveWidgetData<String>("${widgetId}_to", to);
await HomeWidget.saveWidgetData<String>("${widgetId}_rate", currency.rate.toString()); await HomeWidget.saveWidgetData<String>("${widgetId}_rate", currency.rate.toString());
await HomeWidget.saveWidgetData<bool>("${widgetId}_forced_update", true);
await HomeWidget.updateWidget(name: 'AppWidgetProvider', iOSName: 'AppWidgetProvider'); await HomeWidget.updateWidget(name: 'AppWidgetProvider', iOSName: 'AppWidgetProvider');
} }
@@ -74,6 +75,7 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
title: 'Flutter Demo', title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
theme: ThemeData( theme: ThemeData(
// This is the theme of your application. // This is the theme of your application.
// //

View File

@@ -40,8 +40,8 @@ class MainViewModel extends BaseViewmodel {
(value) { (value) {
conversionRate = value.rate != null ? value.rate! : 0.00; conversionRate = value.rate != null ? value.rate! : 0.00;
onSuccess(value); onSuccess(value);
}, onError: (exception, _) { }).catchError((e) {
onError(exception.message); onError(e.message);
}); });
} }

View File

@@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+1 version: 6.1.1+8
environment: environment:
sdk: '>=2.18.0-190.0.dev <3.0.0' sdk: '>=2.18.0-190.0.dev <3.0.0'

View File

@@ -1,13 +1,7 @@
{ {
"query": { "base": "AUD",
"count": 1 "last_updated": 1675689300,
}, "exchange_rates": {
"results": { "GBP": 0.601188
"AUD_GBP": {
"id": "AUD_GBP",
"fr": "AUD",
"to": "GBP",
"val": 0.601188
}
} }
} }

View File

@@ -25,6 +25,7 @@ import 'repository_test.mocks.dart';
onMissingStub: OnMissingStub.returnDefault), onMissingStub: OnMissingStub.returnDefault),
MockSpec<http.HttpResponse<CurrencyResponse>>( MockSpec<http.HttpResponse<CurrencyResponse>>(
as: #MockCurrencyResponse, onMissingStub: OnMissingStub.returnDefault), as: #MockCurrencyResponse, onMissingStub: OnMissingStub.returnDefault),
MockSpec<HttpException>(onMissingStub: OnMissingStub.returnDefault),
MockSpec<DioError>(onMissingStub: OnMissingStub.returnDefault) MockSpec<DioError>(onMissingStub: OnMissingStub.returnDefault)
]) ])
void main() { void main() {
@@ -64,11 +65,10 @@ void main() {
ResponseObject responseObject = ResponseObject.fromJson( ResponseObject responseObject = ResponseObject.fromJson(
await readJson("test/resources/success_call_api")); await readJson("test/resources/success_call_api"));
Currency currencyObject = Currency("AUD", "GBP", 0.601188); Currency currencyObject = Currency("AUD", "GBP", 0.601188);
String currency = "AUD_GBP";
// When // When
when(mockResponse.data).thenReturn(responseObject); when(mockResponse.data).thenReturn(responseObject);
when(currencyApi.getConversion(currency)) when(currencyApi.getConversion("AUD", "GBP"))
.thenAnswer((_) async => mockResponse); .thenAnswer((_) async => mockResponse);
// Then // Then
@@ -83,11 +83,10 @@ void main() {
CurrencyResponse currencyResponse = CurrencyResponse.fromJson( CurrencyResponse currencyResponse = CurrencyResponse.fromJson(
await readJson("test/resources/success_call_backup_api")); await readJson("test/resources/success_call_backup_api"));
Currency currencyObject = Currency("AUD", "GBP", 0.601188); Currency currencyObject = Currency("AUD", "GBP", 0.601188);
String currency = "AUD_GBP";
// When // When
when(currencyApi.getConversion(currency)) when(currencyApi.getConversion("AUD", "GBP"))
.thenAnswer((_) async => Future.error(MockDioError())); .thenAnswer((_) async => Future.error(MockHttpException()));
when(mockResponse.data).thenReturn(currencyResponse); when(mockResponse.data).thenReturn(currencyResponse);
when(backupCurrencyApi.getCurrencyRate("AUD", "GBP")) when(backupCurrencyApi.getCurrencyRate("AUD", "GBP"))
.thenAnswer((_) async => mockResponse); .thenAnswer((_) async => mockResponse);
@@ -100,20 +99,20 @@ void main() {
test('unable to retrieve rate from both APIs', () async { test('unable to retrieve rate from both APIs', () async {
// Given // Given
String currency = "AUD_GBP"; MockDioError backUpError = MockDioError();
DioError backUpError = MockDioError();
// When // When
when(backUpError.error).thenReturn("Error message"); when(backUpError.message).thenReturn("Error message");
when(currencyApi.getConversion(currency)) when(currencyApi.getConversion("AUD", "GBP"))
.thenAnswer((_) async => Future.error(MockDioError())); .thenAnswer((_) async => Future.error(MockDioError()));
when(backupCurrencyApi.getCurrencyRate("AUD", "GBP")) when(backupCurrencyApi.getCurrencyRate("AUD", "GBP"))
.thenAnswer((_) async => Future.error(backUpError)); .thenAnswer((_) async => Future.error(backUpError));
// Then // Then
expect(() async => await sut.getConversationRateFromApi(fromCurrency, toCurrency), expect(
throwsA(predicate((e) => () async =>
e is HttpException && await sut.getConversationRateFromApi(fromCurrency, toCurrency),
e.message == 'Error message'))); throwsA(predicate(
(e) => e is HttpException && e.message == 'Error message')));
}); });
} }

View File

@@ -55,8 +55,8 @@ void main() {
// Then // Then
String fromSelection = mainViewModel.getConversionPair(SelectionType.conversionFrom); String fromSelection = mainViewModel.getConversionPair(SelectionType.conversionFrom);
String toSelection = mainViewModel.getConversionPair(SelectionType.conversionTo); String toSelection = mainViewModel.getConversionPair(SelectionType.conversionTo);
expect(fromSelection, "ALL - Albanian Lek"); expect(fromSelection, "DZD - Algerian Dinar");
expect(toSelection, "ALL - Albanian Lek"); expect(toSelection, "DZD - Algerian Dinar");
}); });
test('set the currency rate from API', () async{ test('set the currency rate from API', () async{