commit a9da34b5920b60c97fe4b0a0580744fefbe2770d
Author: Guilherme Dias Azevedo Praça <240408@MacBook-Pro-9.local>
Date: Mon Nov 3 11:57:51 2025 +0000
first commit
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..aa724b7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,15 @@
+*.iml
+.gradle
+/local.properties
+/.idea/caches
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+/.idea/navEditor.xml
+/.idea/assetWizardSettings.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
+.cxx
+local.properties
diff --git a/.idea/AndroidProjectSystem.xml b/.idea/AndroidProjectSystem.xml
new file mode 100644
index 0000000..4a53bee
--- /dev/null
+++ b/.idea/AndroidProjectSystem.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..b86273d
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml
new file mode 100644
index 0000000..07b225a
--- /dev/null
+++ b/.idea/deploymentTargetSelector.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..639c779
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..2cdc89a
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml
new file mode 100644
index 0000000..16660f1
--- /dev/null
+++ b/.idea/runConfigurations.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/INSTRUCOES_USO.md b/INSTRUCOES_USO.md
new file mode 100644
index 0000000..cfe911f
--- /dev/null
+++ b/INSTRUCOES_USO.md
@@ -0,0 +1,206 @@
+# 📱 Conversor de Moedas - Instruções de Uso
+
+## 🚀 Como Executar o Aplicativo
+
+### Pré-requisitos
+- Android Studio instalado
+- Android SDK configurado
+- Dispositivo Android ou emulador
+
+### Passos para Executar
+
+1. **Abrir o Projeto**
+ ```bash
+ # Navegar para o diretório do projeto
+ cd /Users/240408/AndroidStudioProjects/conversordemoedas2
+
+ # Abrir no Android Studio
+ open -a "Android Studio" .
+ ```
+
+2. **Sincronizar Dependências**
+ - O Android Studio irá sincronizar automaticamente
+ - Ou execute: `./gradlew build`
+
+3. **Executar o App**
+ - Conecte um dispositivo Android ou inicie um emulador
+ - Clique em "Run" (▶️) no Android Studio
+ - Ou execute: `./gradlew installDebug`
+
+## 💱 Como Usar o Conversor
+
+### Interface Principal
+
+1. **Campo de Valor**
+ - Digite o valor que deseja converter
+ - Aceita números decimais (ex: 100.50)
+ - Valores devem ser positivos
+
+2. **Seleção de Moedas**
+ - **De**: Moeda de origem (padrão: USD)
+ - **Para**: Moeda de destino (padrão: BRL)
+ - Use os spinners para selecionar
+
+3. **Conversão**
+ - Clique no botão "Converter"
+ - O resultado aparecerá abaixo do botão
+ - Formato: símbolo + valor (ex: R$ 520.00)
+
+4. **Taxa de Câmbio**
+ - Mostra a taxa atual entre as moedas selecionadas
+ - Atualiza automaticamente ao mudar as moedas
+
+5. **Histórico**
+ - Lista as últimas 50 conversões realizadas
+ - Mostra: valor original, resultado e data/hora
+ - Botão "Limpar" para apagar o histórico
+
+## 🗄️ Banco de Dados SQLite
+
+### Estrutura das Tabelas
+
+#### Tabela `currencies`
+```sql
+CREATE TABLE currencies (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ code TEXT UNIQUE NOT NULL, -- Código da moeda (USD, BRL, etc.)
+ name TEXT NOT NULL, -- Nome completo
+ symbol TEXT NOT NULL, -- Símbolo ($, R$, €, etc.)
+ rate_to_usd REAL NOT NULL -- Taxa em relação ao USD
+);
+```
+
+#### Tabela `conversions`
+```sql
+CREATE TABLE conversions (
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
+ from_currency TEXT NOT NULL, -- Moeda de origem
+ to_currency TEXT NOT NULL, -- Moeda de destino
+ amount REAL NOT NULL, -- Valor convertido
+ result REAL NOT NULL, -- Resultado
+ date TEXT NOT NULL -- Timestamp da conversão
+);
+```
+
+### Moedas Pré-cadastradas
+
+| Código | Nome | Símbolo | Taxa USD |
+|--------|------|---------|----------|
+| USD | Dólar Americano | $ | 1.0 |
+| BRL | Real Brasileiro | R$ | 5.2 |
+| EUR | Euro | € | 0.85 |
+| GBP | Libra Esterlina | £ | 0.73 |
+| JPY | Iene Japonês | ¥ | 110.0 |
+| CAD | Dólar Canadense | C$ | 1.25 |
+| AUD | Dólar Australiano | A$ | 1.35 |
+| CHF | Franco Suíço | CHF | 0.92 |
+| CNY | Yuan Chinês | ¥ | 6.45 |
+| MXN | Peso Mexicano | $ | 20.0 |
+
+## 🔧 Funcionalidades Técnicas
+
+### Conversão de Moedas
+- **Algoritmo**: Conversão via USD como moeda intermediária
+- **Fórmula**: `resultado = (valor / taxa_origem) * taxa_destino`
+- **Precisão**: Dupla precisão para cálculos
+
+### Persistência
+- **SQLite**: Banco local no dispositivo
+- **Criação**: Automática na primeira execução
+- **Dados**: Inserção automática das moedas padrão
+
+### Interface
+- **Material Design**: Componentes modernos
+- **Responsiva**: Adaptável a diferentes telas
+- **Validação**: Entrada de dados segura
+
+## 🧪 Testando o Aplicativo
+
+### Testes Manuais
+
+1. **Conversão Básica**
+ - Valor: 100
+ - De: USD
+ - Para: BRL
+ - Resultado esperado: R$ 520.00
+
+2. **Conversão Decimal**
+ - Valor: 99.99
+ - De: EUR
+ - Para: JPY
+ - Verificar precisão do cálculo
+
+3. **Mesma Moeda**
+ - Valor: 50
+ - De: USD
+ - Para: USD
+ - Resultado: $ 50.00
+
+4. **Histórico**
+ - Realizar várias conversões
+ - Verificar se aparecem no histórico
+ - Testar botão "Limpar"
+
+### Testes Automatizados
+
+Para executar os testes de demonstração:
+
+```java
+// Na MainActivity, descomente esta linha:
+CurrencyConverterDemo.runDemo(this);
+```
+
+Isso executará testes automáticos e mostrará os resultados no log.
+
+## 🐛 Solução de Problemas
+
+### Problemas Comuns
+
+1. **App não compila**
+ - Verificar se todas as dependências estão instaladas
+ - Executar `./gradlew clean` e `./gradlew build`
+
+2. **Conversão não funciona**
+ - Verificar se o valor é positivo
+ - Confirmar se as moedas estão selecionadas
+
+3. **Histórico vazio**
+ - Normal na primeira execução
+ - Realizar algumas conversões primeiro
+
+4. **Taxa de câmbio incorreta**
+ - As taxas são fixas e podem não refletir valores reais
+ - Para valores reais, integrar com API de câmbio
+
+### Logs de Debug
+
+Para ver logs detalhados:
+```bash
+adb logcat | grep CurrencyConverter
+```
+
+## 📈 Melhorias Futuras
+
+- [ ] Integração com API de câmbio em tempo real
+- [ ] Gráficos de histórico de conversões
+- [ ] Notificações de mudanças de taxa
+- [ ] Suporte a mais moedas
+- [ ] Modo offline/online
+- [ ] Backup e sincronização de dados
+- [ ] Temas claro/escuro
+- [ ] Calculadora de taxas
+- [ ] Favoritos de conversões
+- [ ] Exportar histórico
+
+## 📞 Suporte
+
+Para dúvidas ou problemas:
+1. Verificar os logs do Android
+2. Testar com valores simples primeiro
+3. Verificar se o banco de dados foi criado corretamente
+4. Consultar a documentação do código
+
+---
+
+**Desenvolvido com ❤️ usando Android SDK, SQLite e Material Design**
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..1246b0c
--- /dev/null
+++ b/README.md
@@ -0,0 +1,113 @@
+# Conversor de Moedas - Android SQLite
+
+Um aplicativo Android completo para conversão de moedas usando SQLite como banco de dados local.
+
+## Funcionalidades
+
+- **Conversão de Moedas**: Converte valores entre diferentes moedas usando taxas de câmbio pré-definidas
+- **Banco de Dados SQLite**: Armazena moedas e histórico de conversões localmente
+- **Histórico de Conversões**: Visualiza e gerencia o histórico de conversões realizadas
+- **Taxa de Câmbio**: Mostra a taxa de câmbio atual entre as moedas selecionadas
+- **Interface Intuitiva**: Design moderno com Material Design
+
+## Moedas Suportadas
+
+- USD - Dólar Americano ($)
+- BRL - Real Brasileiro (R$)
+- EUR - Euro (€)
+- GBP - Libra Esterlina (£)
+- JPY - Iene Japonês (¥)
+- CAD - Dólar Canadense (C$)
+- AUD - Dólar Australiano (A$)
+- CHF - Franco Suíço (CHF)
+- CNY - Yuan Chinês (¥)
+- MXN - Peso Mexicano ($)
+
+## Estrutura do Projeto
+
+### Classes Principais
+
+1. **DatabaseHelper**: Gerencia o banco de dados SQLite
+ - Criação e atualização das tabelas
+ - Operações CRUD para moedas e conversões
+ - Inserção de dados padrão
+
+2. **CurrencyConverter**: Lógica de conversão de moedas
+ - Conversão entre moedas
+ - Cálculo de taxas de câmbio
+ - Formatação de valores monetários
+
+3. **Currency**: Modelo de dados para moedas
+ - Código, nome, símbolo e taxa de câmbio
+
+4. **Conversion**: Modelo de dados para conversões
+ - Moedas de origem e destino, valores e data
+
+5. **ConversionHistoryAdapter**: Adapter para ListView do histórico
+
+### Banco de Dados
+
+#### Tabela `currencies`
+- `id`: Chave primária
+- `code`: Código da moeda (ex: USD, BRL)
+- `name`: Nome da moeda
+- `symbol`: Símbolo da moeda
+- `rate_to_usd`: Taxa de câmbio em relação ao USD
+
+#### Tabela `conversions`
+- `id`: Chave primária
+- `from_currency`: Moeda de origem
+- `to_currency`: Moeda de destino
+- `amount`: Valor convertido
+- `result`: Resultado da conversão
+- `date`: Data/hora da conversão
+
+## Como Usar
+
+1. **Digite o valor** a ser convertido no campo "Valor"
+2. **Selecione a moeda de origem** no spinner "De"
+3. **Selecione a moeda de destino** no spinner "Para"
+4. **Clique em "Converter"** para realizar a conversão
+5. **Visualize o resultado** na área de resultado
+6. **Consulte o histórico** de conversões na lista abaixo
+7. **Limpe o histórico** usando o botão "Limpar" se necessário
+
+## Tecnologias Utilizadas
+
+- **Android SDK**: Desenvolvimento nativo Android
+- **SQLite**: Banco de dados local
+- **Material Design**: Interface moderna
+- **Java**: Linguagem de programação
+- **ConstraintLayout**: Layout responsivo
+- **CardView**: Componentes visuais
+
+## Instalação
+
+1. Clone o repositório
+2. Abra o projeto no Android Studio
+3. Sincronize as dependências do Gradle
+4. Execute o aplicativo em um dispositivo ou emulador
+
+## Requisitos
+
+- Android API 24+ (Android 7.0)
+- Android Studio
+- Java 11+
+
+## Funcionalidades Técnicas
+
+- **Persistência Local**: Dados armazenados no SQLite
+- **Validação de Entrada**: Verificação de valores válidos
+- **Tratamento de Erros**: Mensagens de erro amigáveis
+- **Interface Responsiva**: Adaptável a diferentes tamanhos de tela
+- **Performance**: Operações otimizadas de banco de dados
+
+## Melhorias Futuras
+
+- Integração com API de câmbio em tempo real
+- Gráficos de histórico de conversões
+- Notificações de mudanças de taxa
+- Suporte a mais moedas
+- Modo offline/online
+- Backup e sincronização de dados
+
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
new file mode 100644
index 0000000..976fb5c
--- /dev/null
+++ b/app/build.gradle.kts
@@ -0,0 +1,45 @@
+plugins {
+ alias(libs.plugins.android.application)
+}
+
+android {
+ namespace = "com.example.conversordemoedas2"
+ compileSdk = 36
+
+ defaultConfig {
+ applicationId = "com.example.conversordemoedas2"
+ minSdk = 24
+ targetSdk = 36
+ versionCode = 1
+ versionName = "1.0"
+
+ testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
+ }
+
+ buildTypes {
+ release {
+ isMinifyEnabled = false
+ proguardFiles(
+ getDefaultProguardFile("proguard-android-optimize.txt"),
+ "proguard-rules.pro"
+ )
+ }
+ }
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_17
+ targetCompatibility = JavaVersion.VERSION_17
+ }
+}
+
+dependencies {
+
+ implementation(libs.appcompat)
+ implementation(libs.material)
+ implementation(libs.activity)
+ implementation(libs.constraintlayout)
+ implementation("androidx.cardview:cardview:1.0.0")
+ implementation("com.google.android.material:material:1.11.0")
+ testImplementation(libs.junit)
+ androidTestImplementation(libs.ext.junit)
+ androidTestImplementation(libs.espresso.core)
+}
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/example/conversordemoedas2/ExampleInstrumentedTest.java b/app/src/androidTest/java/com/example/conversordemoedas2/ExampleInstrumentedTest.java
new file mode 100644
index 0000000..2269f85
--- /dev/null
+++ b/app/src/androidTest/java/com/example/conversordemoedas2/ExampleInstrumentedTest.java
@@ -0,0 +1,26 @@
+package com.example.conversordemoedas2;
+
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.*;
+
+/**
+ * Instrumented test, which will execute on an Android device.
+ *
+ * @see Testing documentation
+ */
+@RunWith(AndroidJUnit4.class)
+public class ExampleInstrumentedTest {
+ @Test
+ public void useAppContext() {
+ // Context of the app under test.
+ Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+ assertEquals("com.example.conversordemoedas2", appContext.getPackageName());
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..6ef3f6c
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/example/conversordemoedas2/AppPreferences.java b/app/src/main/java/com/example/conversordemoedas2/AppPreferences.java
new file mode 100644
index 0000000..2f2cfb9
--- /dev/null
+++ b/app/src/main/java/com/example/conversordemoedas2/AppPreferences.java
@@ -0,0 +1,86 @@
+package com.example.conversordemoedas2;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+/**
+ * Classe para gerenciar configurações e preferências do usuário
+ */
+public class AppPreferences {
+
+ private static final String PREFS_NAME = "CurrencyConverterPrefs";
+ private static final String KEY_DEFAULT_FROM_CURRENCY = "default_from_currency";
+ private static final String KEY_DEFAULT_TO_CURRENCY = "default_to_currency";
+ private static final String KEY_LAST_AMOUNT = "last_amount";
+ private static final String KEY_SHOW_EXCHANGE_RATE = "show_exchange_rate";
+
+ private SharedPreferences preferences;
+
+ public AppPreferences(Context context) {
+ preferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
+ }
+
+ /**
+ * Salva a moeda padrão de origem
+ */
+ public void setDefaultFromCurrency(String currencyCode) {
+ preferences.edit().putString(KEY_DEFAULT_FROM_CURRENCY, currencyCode).apply();
+ }
+
+ /**
+ * Obtém a moeda padrão de origem
+ */
+ public String getDefaultFromCurrency() {
+ return preferences.getString(KEY_DEFAULT_FROM_CURRENCY, "USD");
+ }
+
+ /**
+ * Salva a moeda padrão de destino
+ */
+ public void setDefaultToCurrency(String currencyCode) {
+ preferences.edit().putString(KEY_DEFAULT_TO_CURRENCY, currencyCode).apply();
+ }
+
+ /**
+ * Obtém a moeda padrão de destino
+ */
+ public String getDefaultToCurrency() {
+ return preferences.getString(KEY_DEFAULT_TO_CURRENCY, "BRL");
+ }
+
+ /**
+ * Salva o último valor digitado
+ */
+ public void setLastAmount(double amount) {
+ preferences.edit().putFloat(KEY_LAST_AMOUNT, (float) amount).apply();
+ }
+
+ /**
+ * Obtém o último valor digitado
+ */
+ public double getLastAmount() {
+ return preferences.getFloat(KEY_LAST_AMOUNT, 0.0f);
+ }
+
+ /**
+ * Define se deve mostrar a taxa de câmbio
+ */
+ public void setShowExchangeRate(boolean show) {
+ preferences.edit().putBoolean(KEY_SHOW_EXCHANGE_RATE, show).apply();
+ }
+
+ /**
+ * Verifica se deve mostrar a taxa de câmbio
+ */
+ public boolean getShowExchangeRate() {
+ return preferences.getBoolean(KEY_SHOW_EXCHANGE_RATE, true);
+ }
+
+ /**
+ * Limpa todas as preferências
+ */
+ public void clearAll() {
+ preferences.edit().clear().apply();
+ }
+}
+
diff --git a/app/src/main/java/com/example/conversordemoedas2/Conversion.java b/app/src/main/java/com/example/conversordemoedas2/Conversion.java
new file mode 100644
index 0000000..6a6a649
--- /dev/null
+++ b/app/src/main/java/com/example/conversordemoedas2/Conversion.java
@@ -0,0 +1,52 @@
+package com.example.conversordemoedas2;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+
+public class Conversion {
+ private int id;
+ private String fromCurrency;
+ private String toCurrency;
+ private double amount;
+ private double result;
+ private long date;
+
+ public Conversion(int id, String fromCurrency, String toCurrency,
+ double amount, double result, long date) {
+ this.id = id;
+ this.fromCurrency = fromCurrency;
+ this.toCurrency = toCurrency;
+ this.amount = amount;
+ this.result = result;
+ this.date = date;
+ }
+
+ // Getters
+ public int getId() { return id; }
+ public String getFromCurrency() { return fromCurrency; }
+ public String getToCurrency() { return toCurrency; }
+ public double getAmount() { return amount; }
+ public double getResult() { return result; }
+ public long getDate() { return date; }
+
+ // Setters
+ public void setId(int id) { this.id = id; }
+ public void setFromCurrency(String fromCurrency) { this.fromCurrency = fromCurrency; }
+ public void setToCurrency(String toCurrency) { this.toCurrency = toCurrency; }
+ public void setAmount(double amount) { this.amount = amount; }
+ public void setResult(double result) { this.result = result; }
+ public void setDate(long date) { this.date = date; }
+
+ public String getFormattedDate() {
+ SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm", Locale.getDefault());
+ return sdf.format(new Date(date));
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%.2f %s = %.2f %s (%s)",
+ amount, fromCurrency, result, toCurrency, getFormattedDate());
+ }
+}
+
diff --git a/app/src/main/java/com/example/conversordemoedas2/ConversionHistoryAdapter.java b/app/src/main/java/com/example/conversordemoedas2/ConversionHistoryAdapter.java
new file mode 100644
index 0000000..0b0e0cb
--- /dev/null
+++ b/app/src/main/java/com/example/conversordemoedas2/ConversionHistoryAdapter.java
@@ -0,0 +1,79 @@
+package com.example.conversordemoedas2;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+import java.util.List;
+
+public class ConversionHistoryAdapter extends BaseAdapter {
+ private Context context;
+ private List conversions;
+ private LayoutInflater inflater;
+
+ public ConversionHistoryAdapter(Context context, List conversions) {
+ this.context = context;
+ this.conversions = conversions;
+ this.inflater = LayoutInflater.from(context);
+ }
+
+ @Override
+ public int getCount() {
+ return conversions.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return conversions.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return conversions.get(position).getId();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ ViewHolder holder;
+
+ if (convertView == null) {
+ convertView = inflater.inflate(android.R.layout.simple_list_item_2, parent, false);
+ holder = new ViewHolder();
+ holder.text1 = convertView.findViewById(android.R.id.text1);
+ holder.text2 = convertView.findViewById(android.R.id.text2);
+ convertView.setTag(holder);
+ } else {
+ holder = (ViewHolder) convertView.getTag();
+ }
+
+ Conversion conversion = conversions.get(position);
+
+ // Texto principal: conversão
+ String mainText = String.format("%.2f %s = %.2f %s",
+ conversion.getAmount(),
+ conversion.getFromCurrency(),
+ conversion.getResult(),
+ conversion.getToCurrency());
+
+ // Texto secundário: data
+ String subText = conversion.getFormattedDate();
+
+ holder.text1.setText(mainText);
+ holder.text2.setText(subText);
+
+ return convertView;
+ }
+
+ public void updateData(List newConversions) {
+ this.conversions = newConversions;
+ notifyDataSetChanged();
+ }
+
+ private static class ViewHolder {
+ TextView text1;
+ TextView text2;
+ }
+}
+
diff --git a/app/src/main/java/com/example/conversordemoedas2/Currency.java b/app/src/main/java/com/example/conversordemoedas2/Currency.java
new file mode 100644
index 0000000..2a79c4e
--- /dev/null
+++ b/app/src/main/java/com/example/conversordemoedas2/Currency.java
@@ -0,0 +1,37 @@
+package com.example.conversordemoedas2;
+
+public class Currency {
+ private int id;
+ private String code;
+ private String name;
+ private String symbol;
+ private double rateToUsd;
+
+ public Currency(int id, String code, String name, String symbol, double rateToUsd) {
+ this.id = id;
+ this.code = code;
+ this.name = name;
+ this.symbol = symbol;
+ this.rateToUsd = rateToUsd;
+ }
+
+ // Getters
+ public int getId() { return id; }
+ public String getCode() { return code; }
+ public String getName() { return name; }
+ public String getSymbol() { return symbol; }
+ public double getRateToUsd() { return rateToUsd; }
+
+ // Setters
+ public void setId(int id) { this.id = id; }
+ public void setCode(String code) { this.code = code; }
+ public void setName(String name) { this.name = name; }
+ public void setSymbol(String symbol) { this.symbol = symbol; }
+ public void setRateToUsd(double rateToUsd) { this.rateToUsd = rateToUsd; }
+
+ @Override
+ public String toString() {
+ return code + " - " + name + " (" + symbol + ")";
+ }
+}
+
diff --git a/app/src/main/java/com/example/conversordemoedas2/CurrencyConverter.java b/app/src/main/java/com/example/conversordemoedas2/CurrencyConverter.java
new file mode 100644
index 0000000..d1bfd42
--- /dev/null
+++ b/app/src/main/java/com/example/conversordemoedas2/CurrencyConverter.java
@@ -0,0 +1,127 @@
+package com.example.conversordemoedas2;
+
+import android.content.Context;
+import java.util.List;
+
+public class CurrencyConverter {
+ private DatabaseHelper dbHelper;
+
+ public CurrencyConverter(Context context) {
+ this.dbHelper = new DatabaseHelper(context);
+ initializeDatabase();
+ }
+
+ private void initializeDatabase() {
+ // Seed additional currencies if missing
+ dbHelper.seedAdditionalCurrencies();
+ }
+
+ /**
+ * Converte um valor de uma moeda para outra
+ * @param amount Valor a ser convertido
+ * @param fromCurrencyCode Código da moeda de origem
+ * @param toCurrencyCode Código da moeda de destino
+ * @return Valor convertido
+ */
+ public double convert(double amount, String fromCurrencyCode, String toCurrencyCode) {
+ if (fromCurrencyCode.equals(toCurrencyCode)) {
+ return amount;
+ }
+
+ Currency fromCurrency = dbHelper.getCurrencyByCode(fromCurrencyCode);
+ Currency toCurrency = dbHelper.getCurrencyByCode(toCurrencyCode);
+
+ if (fromCurrency == null || toCurrency == null) {
+ throw new IllegalArgumentException("Moeda não encontrada");
+ }
+
+ // Converter para USD primeiro, depois para a moeda de destino
+ double amountInUsd = amount / fromCurrency.getRateToUsd();
+ double result = amountInUsd * toCurrency.getRateToUsd();
+
+ // Salvar no histórico
+ dbHelper.insertConversion(fromCurrencyCode, toCurrencyCode, amount, result);
+
+ return result;
+ }
+
+ /**
+ * Obtém todas as moedas disponíveis
+ * @return Lista de moedas
+ */
+ public List getAvailableCurrencies() {
+ return dbHelper.getAllCurrencies();
+ }
+
+ /**
+ * Obtém o histórico de conversões
+ * @return Lista de conversões
+ */
+ public List getConversionHistory() {
+ return dbHelper.getConversionHistory();
+ }
+
+ /**
+ * Limpa o histórico de conversões
+ */
+ public void clearHistory() {
+ dbHelper.clearHistory();
+ }
+
+ /**
+ * Obtém uma moeda pelo código
+ * @param code Código da moeda
+ * @return Objeto Currency ou null se não encontrado
+ */
+ public Currency getCurrencyByCode(String code) {
+ return dbHelper.getCurrencyByCode(code);
+ }
+
+ /**
+ * Formata um valor monetário com símbolo da moeda
+ * @param amount Valor
+ * @param currencyCode Código da moeda
+ * @return String formatada
+ */
+ public String formatCurrency(double amount, String currencyCode) {
+ Currency currency = getCurrencyByCode(currencyCode);
+ if (currency != null) {
+ return String.format("%s %.2f", currency.getSymbol(), amount);
+ }
+ return String.format("%.2f %s", amount, currencyCode);
+ }
+
+ /**
+ * Calcula a taxa de câmbio entre duas moedas
+ * @param fromCurrencyCode Moeda de origem
+ * @param toCurrencyCode Moeda de destino
+ * @return Taxa de câmbio
+ */
+ public double getExchangeRate(String fromCurrencyCode, String toCurrencyCode) {
+ if (fromCurrencyCode.equals(toCurrencyCode)) {
+ return 1.0;
+ }
+
+ Currency fromCurrency = dbHelper.getCurrencyByCode(fromCurrencyCode);
+ Currency toCurrency = dbHelper.getCurrencyByCode(toCurrencyCode);
+
+ if (fromCurrency == null || toCurrency == null) {
+ throw new IllegalArgumentException("Moeda não encontrada");
+ }
+
+ // Taxa = (rate_to_usd_destino) / (rate_to_usd_origem)
+ return toCurrency.getRateToUsd() / fromCurrency.getRateToUsd();
+ }
+
+ /**
+ * Insere uma conversão no histórico
+ * @param fromCurrency Moeda de origem
+ * @param toCurrency Moeda de destino
+ * @param amount Valor convertido
+ * @param result Resultado da conversão
+ * @return ID da conversão inserida
+ */
+ public long insertConversion(String fromCurrency, String toCurrency, double amount, double result) {
+ return dbHelper.insertConversion(fromCurrency, toCurrency, amount, result);
+ }
+}
diff --git a/app/src/main/java/com/example/conversordemoedas2/CurrencyConverterDemo.java b/app/src/main/java/com/example/conversordemoedas2/CurrencyConverterDemo.java
new file mode 100644
index 0000000..c143da3
--- /dev/null
+++ b/app/src/main/java/com/example/conversordemoedas2/CurrencyConverterDemo.java
@@ -0,0 +1,121 @@
+package com.example.conversordemoedas2;
+
+import android.content.Context;
+import android.util.Log;
+import java.util.List;
+
+/**
+ * Classe de demonstração para testar o conversor de moedas
+ * Esta classe pode ser usada para testar as funcionalidades do conversor
+ */
+public class CurrencyConverterDemo {
+
+ private static final String TAG = "CurrencyConverterDemo";
+
+ /**
+ * Demonstra as funcionalidades do conversor de moedas
+ */
+ public static void runDemo(Context context) {
+ Log.d(TAG, "=== DEMONSTRAÇÃO DO CONVERSOR DE MOEDAS ===");
+
+ CurrencyConverter converter = new CurrencyConverter(context);
+
+ // 1. Listar todas as moedas disponíveis
+ Log.d(TAG, "\n1. MOEDAS DISPONÍVEIS:");
+ List currencies = converter.getAvailableCurrencies();
+ for (Currency currency : currencies) {
+ Log.d(TAG, "- " + currency.toString());
+ }
+
+ // 2. Demonstrações de conversão
+ Log.d(TAG, "\n2. EXEMPLOS DE CONVERSÃO:");
+
+ // USD para BRL
+ try {
+ double result1 = converter.convert(100.0, "USD", "BRL");
+ Log.d(TAG, String.format("100 USD = %s", converter.formatCurrency(result1, "BRL")));
+ } catch (Exception e) {
+ Log.e(TAG, "Erro na conversão USD->BRL: " + e.getMessage());
+ }
+
+ // EUR para JPY
+ try {
+ double result2 = converter.convert(50.0, "EUR", "JPY");
+ Log.d(TAG, String.format("50 EUR = %s", converter.formatCurrency(result2, "JPY")));
+ } catch (Exception e) {
+ Log.e(TAG, "Erro na conversão EUR->JPY: " + e.getMessage());
+ }
+
+ // BRL para CAD
+ try {
+ double result3 = converter.convert(1000.0, "BRL", "CAD");
+ Log.d(TAG, String.format("1000 BRL = %s", converter.formatCurrency(result3, "CAD")));
+ } catch (Exception e) {
+ Log.e(TAG, "Erro na conversão BRL->CAD: " + e.getMessage());
+ }
+
+ // 3. Taxas de câmbio
+ Log.d(TAG, "\n3. TAXAS DE CÂMBIO:");
+ try {
+ double rate1 = converter.getExchangeRate("USD", "BRL");
+ Log.d(TAG, String.format("1 USD = %.4f BRL", rate1));
+
+ double rate2 = converter.getExchangeRate("EUR", "USD");
+ Log.d(TAG, String.format("1 EUR = %.4f USD", rate2));
+
+ double rate3 = converter.getExchangeRate("BRL", "EUR");
+ Log.d(TAG, String.format("1 BRL = %.4f EUR", rate3));
+ } catch (Exception e) {
+ Log.e(TAG, "Erro ao calcular taxas: " + e.getMessage());
+ }
+
+ // 4. Histórico de conversões
+ Log.d(TAG, "\n4. HISTÓRICO DE CONVERSÕES:");
+ List history = converter.getConversionHistory();
+ if (history.isEmpty()) {
+ Log.d(TAG, "Nenhuma conversão no histórico ainda.");
+ } else {
+ for (Conversion conversion : history) {
+ Log.d(TAG, "- " + conversion.toString());
+ }
+ }
+
+ Log.d(TAG, "\n=== FIM DA DEMONSTRAÇÃO ===");
+ }
+
+ /**
+ * Testa conversões específicas
+ */
+ public static void testSpecificConversions(Context context) {
+ Log.d(TAG, "=== TESTE DE CONVERSÕES ESPECÍFICAS ===");
+
+ CurrencyConverter converter = new CurrencyConverter(context);
+
+ // Teste 1: Conversão simples
+ testConversion(converter, 1.0, "USD", "BRL", "1 USD para BRL");
+
+ // Teste 2: Conversão com valor alto
+ testConversion(converter, 10000.0, "EUR", "JPY", "10000 EUR para JPY");
+
+ // Teste 3: Conversão com valor decimal
+ testConversion(converter, 99.99, "GBP", "USD", "99.99 GBP para USD");
+
+ // Teste 4: Conversão para a mesma moeda
+ testConversion(converter, 50.0, "USD", "USD", "50 USD para USD (mesma moeda)");
+
+ Log.d(TAG, "=== FIM DOS TESTES ===");
+ }
+
+ private static void testConversion(CurrencyConverter converter, double amount,
+ String from, String to, String description) {
+ try {
+ double result = converter.convert(amount, from, to);
+ String formattedResult = converter.formatCurrency(result, to);
+ Log.d(TAG, String.format("✓ %s: %.2f %s = %s",
+ description, amount, from, formattedResult));
+ } catch (Exception e) {
+ Log.e(TAG, String.format("✗ %s: ERRO - %s", description, e.getMessage()));
+ }
+ }
+}
+
diff --git a/app/src/main/java/com/example/conversordemoedas2/DatabaseHelper.java b/app/src/main/java/com/example/conversordemoedas2/DatabaseHelper.java
new file mode 100644
index 0000000..778861a
--- /dev/null
+++ b/app/src/main/java/com/example/conversordemoedas2/DatabaseHelper.java
@@ -0,0 +1,219 @@
+package com.example.conversordemoedas2;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import java.util.ArrayList;
+import java.util.List;
+
+public class DatabaseHelper extends SQLiteOpenHelper {
+
+ private static final String DATABASE_NAME = "CurrencyConverter.db";
+ private static final int DATABASE_VERSION = 1;
+
+ // Tabela de moedas
+ private static final String TABLE_CURRENCIES = "currencies";
+ private static final String COLUMN_ID = "id";
+ private static final String COLUMN_CODE = "code";
+ private static final String COLUMN_NAME = "name";
+ private static final String COLUMN_SYMBOL = "symbol";
+ private static final String COLUMN_RATE_TO_USD = "rate_to_usd";
+
+ // Tabela de histórico de conversões
+ private static final String TABLE_CONVERSIONS = "conversions";
+ private static final String COLUMN_FROM_CURRENCY = "from_currency";
+ private static final String COLUMN_TO_CURRENCY = "to_currency";
+ private static final String COLUMN_AMOUNT = "amount";
+ private static final String COLUMN_RESULT = "result";
+ private static final String COLUMN_DATE = "date";
+
+ public DatabaseHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ // Criar tabela de moedas
+ String createCurrenciesTable = "CREATE TABLE " + TABLE_CURRENCIES + " (" +
+ COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
+ COLUMN_CODE + " TEXT UNIQUE NOT NULL, " +
+ COLUMN_NAME + " TEXT NOT NULL, " +
+ COLUMN_SYMBOL + " TEXT NOT NULL, " +
+ COLUMN_RATE_TO_USD + " REAL NOT NULL" +
+ ")";
+
+ // Criar tabela de conversões
+ String createConversionsTable = "CREATE TABLE " + TABLE_CONVERSIONS + " (" +
+ COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
+ COLUMN_FROM_CURRENCY + " TEXT NOT NULL, " +
+ COLUMN_TO_CURRENCY + " TEXT NOT NULL, " +
+ COLUMN_AMOUNT + " REAL NOT NULL, " +
+ COLUMN_RESULT + " REAL NOT NULL, " +
+ COLUMN_DATE + " TEXT NOT NULL" +
+ ")";
+
+ db.execSQL(createCurrenciesTable);
+ db.execSQL(createConversionsTable);
+
+ // Inserir moedas padrão
+ insertDefaultCurrencies(db);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_CONVERSIONS);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_CURRENCIES);
+ onCreate(db);
+ }
+
+ private void insertDefaultCurrencies(SQLiteDatabase db) {
+ String[][] currencies = {
+ {"USD", "Dólar Americano", "$", "1.0"},
+ {"BRL", "Real Brasileiro", "R$", "5.2"},
+ {"EUR", "Euro", "€", "0.85"},
+ {"GBP", "Libra Esterlina", "£", "0.73"},
+ {"JPY", "Iene Japonês", "¥", "110.0"},
+ {"CAD", "Dólar Canadense", "C$", "1.25"},
+ {"AUD", "Dólar Australiano", "A$", "1.35"},
+ {"CHF", "Franco Suíço", "CHF", "0.92"},
+ {"CNY", "Yuan Chinês", "¥", "6.45"},
+ {"MXN", "Peso Mexicano", "$", "20.0"}
+ };
+
+ for (String[] currency : currencies) {
+ ContentValues values = new ContentValues();
+ values.put(COLUMN_CODE, currency[0]);
+ values.put(COLUMN_NAME, currency[1]);
+ values.put(COLUMN_SYMBOL, currency[2]);
+ values.put(COLUMN_RATE_TO_USD, Double.parseDouble(currency[3]));
+ db.insert(TABLE_CURRENCIES, null, values);
+ }
+ }
+
+ // Métodos para gerenciar moedas
+ public List getAllCurrencies() {
+ List currencies = new ArrayList<>();
+ SQLiteDatabase db = this.getReadableDatabase();
+ Cursor cursor = db.query(TABLE_CURRENCIES, null, null, null, null, null, COLUMN_NAME);
+
+ if (cursor.moveToFirst()) {
+ do {
+ Currency currency = new Currency(
+ cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_ID)),
+ cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_CODE)),
+ cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_NAME)),
+ cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_SYMBOL)),
+ cursor.getDouble(cursor.getColumnIndexOrThrow(COLUMN_RATE_TO_USD))
+ );
+ currencies.add(currency);
+ } while (cursor.moveToNext());
+ }
+ cursor.close();
+ db.close();
+ return currencies;
+ }
+
+ public Currency getCurrencyByCode(String code) {
+ SQLiteDatabase db = this.getReadableDatabase();
+ Cursor cursor = db.query(TABLE_CURRENCIES, null, COLUMN_CODE + "=?",
+ new String[]{code}, null, null, null);
+
+ Currency currency = null;
+ if (cursor.moveToFirst()) {
+ currency = new Currency(
+ cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_ID)),
+ cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_CODE)),
+ cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_NAME)),
+ cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_SYMBOL)),
+ cursor.getDouble(cursor.getColumnIndexOrThrow(COLUMN_RATE_TO_USD))
+ );
+ }
+ cursor.close();
+ db.close();
+ return currency;
+ }
+
+ public void seedAdditionalCurrencies() {
+ SQLiteDatabase db = this.getWritableDatabase();
+ String[][] more = new String[][]{
+ {"ARS","Peso Argentino","$","970.0"},
+ {"CLP","Peso Chileno","$","920.0"},
+ {"COP","Peso Colombiano","$","4100.0"},
+ {"INR","Rúpia Indiana","₹","83.0"},
+ {"ZAR","Rand Sul-Africano","R","18.5"},
+ {"TRY","Lira Turca","₺","34.0"},
+ {"RUB","Rublo Russo","₽","95.0"},
+ {"KRW","Won Sul-Coreano","₩","1350.0"},
+ {"SEK","Coroa Sueca","kr","10.5"},
+ {"NOK","Coroa Norueguesa","kr","10.8"},
+ {"DKK","Coroa Dinamarquesa","kr","6.9"},
+ {"PLN","Zlóti Polonês","zł","4.0"},
+ {"CZK","Coroa Checa","Kč","23.0"},
+ {"HUF","Florim Húngaro","Ft","370.0"},
+ {"ILS","Novo Shekel Israelense","₪","3.8"},
+ {"AED","Dirham dos EAU","د.إ","3.67"},
+ {"SAR","Rial Saudita","﷼","3.75"},
+ {"NZD","Dólar Neozelandês","NZ$","1.60"},
+ {"SGD","Dólar de Cingapura","S$","1.35"},
+ {"HKD","Dólar de Hong Kong","HK$","7.80"}
+ };
+ for (String[] c : more) {
+ ContentValues v = new ContentValues();
+ v.put(COLUMN_CODE, c[0]);
+ v.put(COLUMN_NAME, c[1]);
+ v.put(COLUMN_SYMBOL, c[2]);
+ v.put(COLUMN_RATE_TO_USD, Double.parseDouble(c[3]));
+ db.insertWithOnConflict(TABLE_CURRENCIES, null, v, SQLiteDatabase.CONFLICT_IGNORE);
+ }
+ db.close();
+ }
+
+ // Métodos para gerenciar conversões
+ public long insertConversion(String fromCurrency, String toCurrency,
+ double amount, double result) {
+ SQLiteDatabase db = this.getWritableDatabase();
+ ContentValues values = new ContentValues();
+ values.put(COLUMN_FROM_CURRENCY, fromCurrency);
+ values.put(COLUMN_TO_CURRENCY, toCurrency);
+ values.put(COLUMN_AMOUNT, amount);
+ values.put(COLUMN_RESULT, result);
+ values.put(COLUMN_DATE, System.currentTimeMillis());
+
+ long id = db.insert(TABLE_CONVERSIONS, null, values);
+ db.close();
+ return id;
+ }
+
+ public List getConversionHistory() {
+ List conversions = new ArrayList<>();
+ SQLiteDatabase db = this.getReadableDatabase();
+ Cursor cursor = db.query(TABLE_CONVERSIONS, null, null, null, null, null,
+ COLUMN_DATE + " DESC", "50");
+
+ if (cursor.moveToFirst()) {
+ do {
+ Conversion conversion = new Conversion(
+ cursor.getInt(cursor.getColumnIndexOrThrow(COLUMN_ID)),
+ cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_FROM_CURRENCY)),
+ cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_TO_CURRENCY)),
+ cursor.getDouble(cursor.getColumnIndexOrThrow(COLUMN_AMOUNT)),
+ cursor.getDouble(cursor.getColumnIndexOrThrow(COLUMN_RESULT)),
+ cursor.getLong(cursor.getColumnIndexOrThrow(COLUMN_DATE))
+ );
+ conversions.add(conversion);
+ } while (cursor.moveToNext());
+ }
+ cursor.close();
+ db.close();
+ return conversions;
+ }
+
+ public void clearHistory() {
+ SQLiteDatabase db = this.getWritableDatabase();
+ db.delete(TABLE_CONVERSIONS, null, null);
+ db.close();
+ }
+}
+
diff --git a/app/src/main/java/com/example/conversordemoedas2/MainActivity.java b/app/src/main/java/com/example/conversordemoedas2/MainActivity.java
new file mode 100644
index 0000000..c24d24d
--- /dev/null
+++ b/app/src/main/java/com/example/conversordemoedas2/MainActivity.java
@@ -0,0 +1,266 @@
+package com.example.conversordemoedas2;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.Spinner;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.activity.EdgeToEdge;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.graphics.Insets;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
+
+import com.google.android.material.button.MaterialButton;
+import com.google.android.material.textfield.TextInputEditText;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MainActivity extends AppCompatActivity {
+
+ private CurrencyConverter currencyConverter;
+ private TextInputEditText amountInput;
+ private Spinner fromCurrencySpinner;
+ private Spinner toCurrencySpinner;
+ private TextView resultText;
+ private TextView exchangeRateText;
+ private MaterialButton clearHistoryButton;
+ private ListView historyListView;
+ private ImageView swapButton;
+ private MaterialButton speedConverterButton;
+
+ private List currencies;
+ private ConversionHistoryAdapter historyAdapter;
+ private boolean isUpdating = false;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ EdgeToEdge.enable(this);
+ setContentView(R.layout.activity_main);
+ ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main), (v, insets) -> {
+ Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
+ v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
+ return insets;
+ });
+
+ initializeViews();
+ initializeCurrencyConverter();
+ setupSpinners();
+ setupListeners();
+ loadHistory();
+
+ // Executar demonstração no log (opcional)
+ // CurrencyConverterDemo.runDemo(this);
+ }
+
+ private void initializeViews() {
+ amountInput = findViewById(R.id.amountInput);
+ fromCurrencySpinner = findViewById(R.id.fromCurrencySpinner);
+ toCurrencySpinner = findViewById(R.id.toCurrencySpinner);
+ resultText = findViewById(R.id.resultText);
+ exchangeRateText = findViewById(R.id.exchangeRateText);
+ clearHistoryButton = findViewById(R.id.clearHistoryButton);
+ historyListView = findViewById(R.id.historyListView);
+ swapButton = findViewById(R.id.swapButton);
+ speedConverterButton = findViewById(R.id.speedConverterButton);
+ }
+
+ private void initializeCurrencyConverter() {
+ currencyConverter = new CurrencyConverter(this);
+ currencies = currencyConverter.getAvailableCurrencies();
+ }
+
+ private void setupSpinners() {
+ // Criar lista de strings para os spinners
+ List currencyStrings = new ArrayList<>();
+ for (Currency currency : currencies) {
+ currencyStrings.add(currency.toString());
+ }
+
+ ArrayAdapter adapter = new ArrayAdapter<>(this,
+ android.R.layout.simple_spinner_item, currencyStrings);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+
+ fromCurrencySpinner.setAdapter(adapter);
+ toCurrencySpinner.setAdapter(adapter);
+
+ // Selecionar USD como padrão para origem e BRL para destino
+ for (int i = 0; i < currencies.size(); i++) {
+ if (currencies.get(i).getCode().equals("USD")) {
+ fromCurrencySpinner.setSelection(i);
+ }
+ if (currencies.get(i).getCode().equals("BRL")) {
+ toCurrencySpinner.setSelection(i);
+ }
+ }
+
+ // Atualizar conversão quando as moedas mudarem
+ fromCurrencySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ if (!isUpdating) {
+ updateConversion();
+ updateExchangeRate();
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parent) {}
+ });
+
+ toCurrencySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ if (!isUpdating) {
+ updateConversion();
+ updateExchangeRate();
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parent) {}
+ });
+ }
+
+ private void setupListeners() {
+ // Conversão automática quando o texto muda
+ amountInput.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ updateConversion();
+ }
+ });
+
+ // Botão de trocar moedas
+ swapButton.setOnClickListener(v -> swapCurrencies());
+
+ // Botão limpar histórico
+ clearHistoryButton.setOnClickListener(v -> clearHistory());
+
+ // Botão conversor de velocidade
+ speedConverterButton.setOnClickListener(v -> {
+ Intent intent = new Intent(MainActivity.this, SpeedConverterActivity.class);
+ startActivity(intent);
+ });
+
+ // Botão conversor de medidas
+ MaterialButton measurementConverterButton = findViewById(R.id.measurementConverterButton);
+ measurementConverterButton.setOnClickListener(v -> {
+ Intent intent = new Intent(MainActivity.this, MeasurementConverterActivity.class);
+ startActivity(intent);
+ });
+ }
+
+ private void updateConversion() {
+ String amountString = amountInput.getText().toString().trim();
+
+ if (TextUtils.isEmpty(amountString)) {
+ resultText.setText("Digite um valor para converter");
+ resultText.setTextColor(getResources().getColor(R.color.text_secondary));
+ return;
+ }
+
+ try {
+ double amount = Double.parseDouble(amountString);
+
+ if (amount <= 0) {
+ resultText.setText("Digite um valor positivo");
+ resultText.setTextColor(getResources().getColor(R.color.error_color));
+ return;
+ }
+
+ Currency fromCurrency = currencies.get(fromCurrencySpinner.getSelectedItemPosition());
+ Currency toCurrency = currencies.get(toCurrencySpinner.getSelectedItemPosition());
+
+ double result = currencyConverter.convert(amount, fromCurrency.getCode(), toCurrency.getCode());
+
+ // Mostrar resultado com animação
+ String formattedResult = currencyConverter.formatCurrency(result, toCurrency.getCode());
+ resultText.setText(formattedResult);
+ resultText.setTextColor(getResources().getColor(R.color.primary_color));
+
+ // Animação suave
+ resultText.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_in));
+
+ // Salvar no histórico apenas se for uma conversão válida
+ if (amount > 0) {
+ currencyConverter.insertConversion(fromCurrency.getCode(), toCurrency.getCode(), amount, result);
+ loadHistory();
+ }
+
+ } catch (NumberFormatException e) {
+ resultText.setText("Digite um valor válido");
+ resultText.setTextColor(getResources().getColor(R.color.error_color));
+ } catch (Exception e) {
+ resultText.setText("Erro na conversão");
+ resultText.setTextColor(getResources().getColor(R.color.error_color));
+ }
+ }
+
+ private void swapCurrencies() {
+ isUpdating = true;
+
+ int fromPosition = fromCurrencySpinner.getSelectedItemPosition();
+ int toPosition = toCurrencySpinner.getSelectedItemPosition();
+
+ fromCurrencySpinner.setSelection(toPosition);
+ toCurrencySpinner.setSelection(fromPosition);
+
+ // Animação do botão
+ swapButton.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_in));
+
+ isUpdating = false;
+
+ // Atualizar conversão após a troca
+ updateConversion();
+ updateExchangeRate();
+
+ Toast.makeText(this, "Moedas trocadas!", Toast.LENGTH_SHORT).show();
+ }
+
+ private void updateExchangeRate() {
+ try {
+ Currency fromCurrency = currencies.get(fromCurrencySpinner.getSelectedItemPosition());
+ Currency toCurrency = currencies.get(toCurrencySpinner.getSelectedItemPosition());
+
+ double rate = currencyConverter.getExchangeRate(fromCurrency.getCode(), toCurrency.getCode());
+
+ String rateText = String.format("1 %s = %.4f %s",
+ fromCurrency.getCode(), rate, toCurrency.getCode());
+ exchangeRateText.setText(rateText);
+
+ } catch (Exception e) {
+ exchangeRateText.setText("Erro ao calcular taxa");
+ }
+ }
+
+ private void loadHistory() {
+ List history = currencyConverter.getConversionHistory();
+ historyAdapter = new ConversionHistoryAdapter(this, history);
+ historyListView.setAdapter(historyAdapter);
+ }
+
+ private void clearHistory() {
+ currencyConverter.clearHistory();
+ loadHistory();
+ Toast.makeText(this, "Histórico limpo", Toast.LENGTH_SHORT).show();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/conversordemoedas2/MeasurementConverter.java b/app/src/main/java/com/example/conversordemoedas2/MeasurementConverter.java
new file mode 100644
index 0000000..69f619e
--- /dev/null
+++ b/app/src/main/java/com/example/conversordemoedas2/MeasurementConverter.java
@@ -0,0 +1,93 @@
+package com.example.conversordemoedas2;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+public class MeasurementConverter {
+
+ private static final String CAT_LENGTH = "Comprimento";
+ private static final String CAT_WEIGHT = "Peso";
+ private static final String CAT_TEMPERATURE = "Temperatura";
+
+ private static final List LENGTH_UNITS = Arrays.asList("mm","cm","m","km","in","ft","yd","mi");
+ private static final List WEIGHT_UNITS = Arrays.asList("mg","g","kg","t","oz","lb");
+ private static final List TEMP_UNITS = Arrays.asList("°C","°F","K");
+
+ private static final Map LENGTH_TO_METER = new LinkedHashMap<>();
+ private static final Map WEIGHT_TO_KG = new LinkedHashMap<>();
+
+ static {
+ // Comprimento -> metros
+ LENGTH_TO_METER.put("mm", 0.001);
+ LENGTH_TO_METER.put("cm", 0.01);
+ LENGTH_TO_METER.put("m", 1.0);
+ LENGTH_TO_METER.put("km", 1000.0);
+ LENGTH_TO_METER.put("in", 0.0254);
+ LENGTH_TO_METER.put("ft", 0.3048);
+ LENGTH_TO_METER.put("yd", 0.9144);
+ LENGTH_TO_METER.put("mi", 1609.344);
+
+ // Peso -> quilogramas
+ WEIGHT_TO_KG.put("mg", 0.000001);
+ WEIGHT_TO_KG.put("g", 0.001);
+ WEIGHT_TO_KG.put("kg", 1.0);
+ WEIGHT_TO_KG.put("t", 1000.0);
+ WEIGHT_TO_KG.put("oz", 0.028349523125);
+ WEIGHT_TO_KG.put("lb", 0.45359237);
+ }
+
+ public List getUnitsForCategory(String category) {
+ if (CAT_LENGTH.equals(category)) return new ArrayList<>(LENGTH_UNITS);
+ if (CAT_WEIGHT.equals(category)) return new ArrayList<>(WEIGHT_UNITS);
+ if (CAT_TEMPERATURE.equals(category)) return new ArrayList<>(TEMP_UNITS);
+ return new ArrayList<>();
+ }
+
+ public double convert(String category, double value, String from, String to) {
+ if (from.equals(to)) return value;
+ if (CAT_LENGTH.equals(category)) {
+ double meters = value * LENGTH_TO_METER.get(from);
+ return meters / LENGTH_TO_METER.get(to);
+ }
+ if (CAT_WEIGHT.equals(category)) {
+ double kg = value * WEIGHT_TO_KG.get(from);
+ return kg / WEIGHT_TO_KG.get(to);
+ }
+ if (CAT_TEMPERATURE.equals(category)) {
+ // normalize to Celsius
+ double c;
+ if ("°C".equals(from)) c = value;
+ else if ("°F".equals(from)) c = (value - 32.0) * 5.0 / 9.0;
+ else c = value - 273.15; // K -> C
+ if ("°C".equals(to)) return c;
+ if ("°F".equals(to)) return c * 9.0 / 5.0 + 32.0;
+ return c + 273.15; // to K
+ }
+ throw new IllegalArgumentException("Categoria inválida");
+ }
+
+ public double rate(String category, String from, String to) {
+ if (from.equals(to)) return 1.0;
+ if (CAT_LENGTH.equals(category)) {
+ return LENGTH_TO_METER.get(from) / LENGTH_TO_METER.get(to);
+ }
+ if (CAT_WEIGHT.equals(category)) {
+ return WEIGHT_TO_KG.get(from) / WEIGHT_TO_KG.get(to);
+ }
+ if (CAT_TEMPERATURE.equals(category)) {
+ // temperature rates aren't constant; show delta conversion for 1 unit
+ return convert(category, 1.0, from, to);
+ }
+ return 1.0;
+ }
+
+ public String format(String category, double value, String unit) {
+ if (CAT_TEMPERATURE.equals(category)) {
+ return String.format("%.2f %s", value, unit);
+ }
+ return String.format("%.4f %s", value, unit);
+ }
+}
diff --git a/app/src/main/java/com/example/conversordemoedas2/MeasurementConverterActivity.java b/app/src/main/java/com/example/conversordemoedas2/MeasurementConverterActivity.java
new file mode 100644
index 0000000..bd7c4a0
--- /dev/null
+++ b/app/src/main/java/com/example/conversordemoedas2/MeasurementConverterActivity.java
@@ -0,0 +1,170 @@
+package com.example.conversordemoedas2;
+
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.text.TextUtils;
+import android.view.animation.AnimationUtils;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import androidx.activity.EdgeToEdge;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.graphics.Insets;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
+
+import com.google.android.material.textfield.TextInputEditText;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+public class MeasurementConverterActivity extends AppCompatActivity {
+
+ private MeasurementConverter measurementConverter;
+ private Spinner categorySpinner;
+ private Spinner fromUnitSpinner;
+ private Spinner toUnitSpinner;
+ private TextInputEditText amountInput;
+ private TextView resultText;
+ private TextView rateText;
+
+ private List categories;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ EdgeToEdge.enable(this);
+ setContentView(R.layout.fragment_measurement_converter);
+ ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.measureMain), (v, insets) -> {
+ Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
+ v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
+ return insets;
+ });
+
+ initializeViews();
+ initializeConverter();
+ setupCategorySpinner();
+ setupListeners();
+ }
+
+ private void initializeViews() {
+ categorySpinner = findViewById(R.id.categorySpinner);
+ fromUnitSpinner = findViewById(R.id.measureFromUnitSpinner);
+ toUnitSpinner = findViewById(R.id.measureToUnitSpinner);
+ amountInput = findViewById(R.id.measureAmountInput);
+ resultText = findViewById(R.id.measureResultText);
+ rateText = findViewById(R.id.measureRateText);
+
+ findViewById(R.id.openCurrencyConverterButton).setOnClickListener(v -> {
+ startActivity(new android.content.Intent(this, MainActivity.class));
+ });
+ findViewById(R.id.openSpeedConverterButton).setOnClickListener(v -> {
+ startActivity(new android.content.Intent(this, SpeedConverterActivity.class));
+ });
+ }
+
+ private void initializeConverter() {
+ measurementConverter = new MeasurementConverter();
+ categories = new ArrayList<>(Arrays.asList("Comprimento", "Peso", "Temperatura"));
+ }
+
+ private void setupCategorySpinner() {
+ ArrayAdapter categoryAdapter = new ArrayAdapter<>(this,
+ android.R.layout.simple_spinner_item, categories);
+ categoryAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ categorySpinner.setAdapter(categoryAdapter);
+
+ categorySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, android.view.View view, int position, long id) {
+ populateUnits();
+ updateConversion();
+ updateRate();
+ }
+ @Override
+ public void onNothingSelected(AdapterView> parent) {}
+ });
+ }
+
+ private void populateUnits() {
+ String category = (String) categorySpinner.getSelectedItem();
+ List units = measurementConverter.getUnitsForCategory(category);
+ ArrayAdapter unitsAdapter = new ArrayAdapter<>(this,
+ android.R.layout.simple_spinner_item, units);
+ unitsAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ fromUnitSpinner.setAdapter(unitsAdapter);
+ toUnitSpinner.setAdapter(unitsAdapter);
+ if (!units.isEmpty()) {
+ fromUnitSpinner.setSelection(0);
+ toUnitSpinner.setSelection(Math.min(1, units.size() - 1));
+ }
+ fromUnitSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, android.view.View view, int position, long id) {
+ updateConversion();
+ updateRate();
+ }
+ @Override
+ public void onNothingSelected(AdapterView> parent) {}
+ });
+ toUnitSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, android.view.View view, int position, long id) {
+ updateConversion();
+ updateRate();
+ }
+ @Override
+ public void onNothingSelected(AdapterView> parent) {}
+ });
+ }
+
+ private void setupListeners() {
+ amountInput.addTextChangedListener(new TextWatcher() {
+ @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+ @Override public void onTextChanged(CharSequence s, int start, int before, int count) {}
+ @Override public void afterTextChanged(Editable s) { updateConversion(); }
+ });
+ }
+
+ private void updateConversion() {
+ String input = amountInput.getText() != null ? amountInput.getText().toString().trim() : "";
+ if (TextUtils.isEmpty(input)) {
+ resultText.setText("Digite um valor para converter");
+ resultText.setTextColor(getResources().getColor(R.color.text_secondary));
+ return;
+ }
+ try {
+ double value = Double.parseDouble(input);
+ String category = (String) categorySpinner.getSelectedItem();
+ String from = (String) fromUnitSpinner.getSelectedItem();
+ String to = (String) toUnitSpinner.getSelectedItem();
+ double result = measurementConverter.convert(category, value, from, to);
+ String formatted = measurementConverter.format(category, result, to);
+ resultText.setText(formatted);
+ resultText.setTextColor(getResources().getColor(R.color.accent_color));
+ resultText.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_in));
+ } catch (NumberFormatException e) {
+ resultText.setText("Digite um valor válido");
+ resultText.setTextColor(getResources().getColor(R.color.error_color));
+ } catch (Exception e) {
+ resultText.setText("Erro na conversão");
+ resultText.setTextColor(getResources().getColor(R.color.error_color));
+ }
+ }
+
+ private void updateRate() {
+ try {
+ String category = (String) categorySpinner.getSelectedItem();
+ String from = (String) fromUnitSpinner.getSelectedItem();
+ String to = (String) toUnitSpinner.getSelectedItem();
+ double rate = measurementConverter.rate(category, from, to);
+ rateText.setText(String.format("1 %s = %.6f %s", from, rate, to));
+ } catch (Exception e) {
+ rateText.setText("Selecione as unidades");
+ }
+ }
+}
diff --git a/app/src/main/java/com/example/conversordemoedas2/SpeedConverter.java b/app/src/main/java/com/example/conversordemoedas2/SpeedConverter.java
new file mode 100644
index 0000000..540b248
--- /dev/null
+++ b/app/src/main/java/com/example/conversordemoedas2/SpeedConverter.java
@@ -0,0 +1,156 @@
+package com.example.conversordemoedas2;
+
+import android.content.Context;
+import java.util.ArrayList;
+import java.util.List;
+
+public class SpeedConverter {
+
+ private DatabaseHelper dbHelper;
+
+ // Unidades de velocidade com fatores de conversão para m/s (metros por segundo)
+ private static final Object[][] SPEED_UNITS = {
+ // ID, Símbolo, Fator para m/s, Descrição
+ {1, "m/s", 1.0, "Metros por segundo"},
+ {2, "km/h", 0.277778, "Quilômetros por hora"},
+ {3, "mph", 0.44704, "Milhas por hora"},
+ {4, "ft/s", 0.3048, "Pés por segundo"},
+ {5, "knot", 0.514444, "Nós"},
+ {6, "mach", 343.0, "Mach"},
+ {7, "c", 299792458.0, "Velocidade da luz"},
+ {8, "fps", 0.3048, "Frames por segundo"},
+ {9, "rpm", 0.10472, "Rotações por minuto"},
+ {10, "deg/s", 0.0174533, "Graus por segundo"}
+ };
+
+ public SpeedConverter(Context context) {
+ this.dbHelper = new DatabaseHelper(context);
+ }
+
+ /**
+ * Converte velocidade de uma unidade para outra
+ * @param value Valor a ser convertido
+ * @param fromUnit Unidade de origem
+ * @param toUnit Unidade de destino
+ * @return Valor convertido
+ */
+ public double convert(double value, String fromUnit, String toUnit) {
+ if (fromUnit.equals(toUnit)) {
+ return value;
+ }
+
+ double fromFactor = getFactor(fromUnit);
+ double toFactor = getFactor(toUnit);
+
+ if (fromFactor == 0 || toFactor == 0) {
+ throw new IllegalArgumentException("Unidade não encontrada");
+ }
+
+ // Converter para m/s primeiro, depois para a unidade de destino
+ double valueInMs = value * fromFactor;
+ double result = valueInMs / toFactor;
+
+ return result;
+ }
+
+ /**
+ * Obtém o fator de conversão para uma unidade
+ * @param unit Unidade de velocidade
+ * @return Fator de conversão
+ */
+ private double getFactor(String unit) {
+ for (Object[] speedUnit : SPEED_UNITS) {
+ if (speedUnit[1].equals(unit)) {
+ return (Double) speedUnit[2];
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Obtém todas as unidades de velocidade disponíveis
+ * @return Lista de unidades
+ */
+ public List getAvailableUnits() {
+ List units = new ArrayList<>();
+ for (Object[] speedUnit : SPEED_UNITS) {
+ units.add(new SpeedUnit(
+ (int) speedUnit[0],
+ (String) speedUnit[1],
+ (String) speedUnit[3],
+ (Double) speedUnit[2]
+ ));
+ }
+ return units;
+ }
+
+ /**
+ * Obtém uma unidade pelo código
+ * @param code Código da unidade
+ * @return Objeto SpeedUnit ou null se não encontrado
+ */
+ public SpeedUnit getUnitByCode(String code) {
+ for (Object[] speedUnit : SPEED_UNITS) {
+ if (speedUnit[1].equals(code)) {
+ return new SpeedUnit(
+ (int) speedUnit[0],
+ (String) speedUnit[1],
+ (String) speedUnit[3],
+ (Double) speedUnit[2]
+ );
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Formata um valor de velocidade com símbolo da unidade
+ * @param value Valor
+ * @param unitCode Código da unidade
+ * @return String formatada
+ */
+ public String formatSpeed(double value, String unitCode) {
+ SpeedUnit unit = getUnitByCode(unitCode);
+ if (unit != null) {
+ return String.format("%.2f %s", value, unit.getSymbol());
+ }
+ return String.format("%.2f %s", value, unitCode);
+ }
+
+ /**
+ * Calcula a taxa de conversão entre duas unidades
+ * @param fromUnit Unidade de origem
+ * @param toUnit Unidade de destino
+ * @return Taxa de conversão
+ */
+ public double getConversionRate(String fromUnit, String toUnit) {
+ if (fromUnit.equals(toUnit)) {
+ return 1.0;
+ }
+
+ double fromFactor = getFactor(fromUnit);
+ double toFactor = getFactor(toUnit);
+
+ if (fromFactor == 0 || toFactor == 0) {
+ throw new IllegalArgumentException("Unidade não encontrada");
+ }
+
+ return fromFactor / toFactor;
+ }
+
+ /**
+ * Obtém exemplos de conversão para demonstração
+ * @return Lista de exemplos
+ */
+ public List getExamples() {
+ List examples = new ArrayList<>();
+ examples.add("🚗 100 km/h = 27.78 m/s");
+ examples.add("✈️ 500 mph = 223.52 m/s");
+ examples.add("🏃 10 m/s = 36 km/h");
+ examples.add("🚢 20 knot = 10.29 m/s");
+ examples.add("🚀 1 mach = 343 m/s");
+ return examples;
+ }
+}
+
+
diff --git a/app/src/main/java/com/example/conversordemoedas2/SpeedConverterActivity.java b/app/src/main/java/com/example/conversordemoedas2/SpeedConverterActivity.java
new file mode 100644
index 0000000..0289c94
--- /dev/null
+++ b/app/src/main/java/com/example/conversordemoedas2/SpeedConverterActivity.java
@@ -0,0 +1,219 @@
+package com.example.conversordemoedas2;
+
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.Spinner;
+import android.widget.TextView;
+
+import androidx.activity.EdgeToEdge;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.core.graphics.Insets;
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
+import androidx.appcompat.widget.Toolbar;
+
+import com.google.android.material.textfield.TextInputEditText;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SpeedConverterActivity extends AppCompatActivity {
+
+ private SpeedConverter speedConverter;
+ private TextInputEditText speedAmountInput;
+ private Spinner fromSpeedSpinner;
+ private Spinner toSpeedSpinner;
+ private TextView speedResultText;
+ private TextView speedRateText;
+ private ImageView speedSwapButton;
+
+ private List speedUnits;
+ private boolean isUpdating = false;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ EdgeToEdge.enable(this);
+ setContentView(R.layout.fragment_speed_converter);
+ ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.speedMain), (v, insets) -> {
+ Insets systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars());
+ v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom);
+ return insets;
+ });
+ // Removida Toolbar!
+ findViewById(R.id.currencyConverterButton).setOnClickListener(v -> finish());
+
+ initializeViews();
+ initializeSpeedConverter();
+ setupSpinners();
+ setupListeners();
+ }
+
+ private void initializeViews() {
+ speedAmountInput = findViewById(R.id.speedAmountInput);
+ fromSpeedSpinner = findViewById(R.id.speedFromUnitSpinner);
+ toSpeedSpinner = findViewById(R.id.speedToUnitSpinner);
+ speedResultText = findViewById(R.id.speedResultText);
+ speedRateText = findViewById(R.id.speedRateText);
+ speedSwapButton = findViewById(R.id.speedSwapButton);
+ }
+
+ private void initializeSpeedConverter() {
+ speedConverter = new SpeedConverter(this);
+ speedUnits = speedConverter.getAvailableUnits();
+ }
+
+ private void setupSpinners() {
+ // Criar lista de strings para os spinners
+ List unitStrings = new ArrayList<>();
+ for (SpeedUnit unit : speedUnits) {
+ unitStrings.add(unit.toString());
+ }
+
+ ArrayAdapter adapter = new ArrayAdapter<>(this,
+ android.R.layout.simple_spinner_item, unitStrings);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+
+ fromSpeedSpinner.setAdapter(adapter);
+ toSpeedSpinner.setAdapter(adapter);
+
+ // Selecionar m/s como padrão para origem e km/h para destino
+ for (int i = 0; i < speedUnits.size(); i++) {
+ if (speedUnits.get(i).getSymbol().equals("m/s")) {
+ fromSpeedSpinner.setSelection(i);
+ }
+ if (speedUnits.get(i).getSymbol().equals("km/h")) {
+ toSpeedSpinner.setSelection(i);
+ }
+ }
+
+ // Atualizar conversão quando as unidades mudarem
+ fromSpeedSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ if (!isUpdating) {
+ updateConversion();
+ updateRate();
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parent) {}
+ });
+
+ toSpeedSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView> parent, View view, int position, long id) {
+ if (!isUpdating) {
+ updateConversion();
+ updateRate();
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView> parent) {}
+ });
+ }
+
+ private void setupListeners() {
+ // Conversão automática quando o texto muda
+ speedAmountInput.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {}
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ updateConversion();
+ }
+ });
+
+ // Botão de trocar unidades
+ speedSwapButton.setOnClickListener(v -> swapUnits());
+ }
+
+ private void updateConversion() {
+ String amountString = speedAmountInput.getText().toString().trim();
+
+ if (TextUtils.isEmpty(amountString)) {
+ speedResultText.setText("Digite um valor para converter");
+ speedResultText.setTextColor(getResources().getColor(R.color.text_secondary));
+ return;
+ }
+
+ try {
+ double amount = Double.parseDouble(amountString);
+
+ if (amount < 0) {
+ speedResultText.setText("Digite um valor positivo");
+ speedResultText.setTextColor(getResources().getColor(R.color.error_color));
+ return;
+ }
+
+ SpeedUnit fromUnit = speedUnits.get(fromSpeedSpinner.getSelectedItemPosition());
+ SpeedUnit toUnit = speedUnits.get(toSpeedSpinner.getSelectedItemPosition());
+
+ double result = speedConverter.convert(amount, fromUnit.getSymbol(), toUnit.getSymbol());
+
+ // Mostrar resultado com animação
+ String formattedResult = speedConverter.formatSpeed(result, toUnit.getSymbol());
+ speedResultText.setText(formattedResult);
+ speedResultText.setTextColor(getResources().getColor(R.color.accent_color));
+
+ // Animação suave
+ speedResultText.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_in));
+
+ } catch (NumberFormatException e) {
+ speedResultText.setText("Digite um valor válido");
+ speedResultText.setTextColor(getResources().getColor(R.color.error_color));
+ } catch (Exception e) {
+ speedResultText.setText("Erro na conversão");
+ speedResultText.setTextColor(getResources().getColor(R.color.error_color));
+ }
+ }
+
+ private void swapUnits() {
+ isUpdating = true;
+
+ int fromPosition = fromSpeedSpinner.getSelectedItemPosition();
+ int toPosition = toSpeedSpinner.getSelectedItemPosition();
+
+ fromSpeedSpinner.setSelection(toPosition);
+ toSpeedSpinner.setSelection(fromPosition);
+
+ // Animação do botão
+ speedSwapButton.startAnimation(AnimationUtils.loadAnimation(this, android.R.anim.fade_in));
+
+ isUpdating = false;
+
+ // Atualizar conversão após a troca
+ updateConversion();
+ updateRate();
+ }
+
+ private void updateRate() {
+ try {
+ SpeedUnit fromUnit = speedUnits.get(fromSpeedSpinner.getSelectedItemPosition());
+ SpeedUnit toUnit = speedUnits.get(toSpeedSpinner.getSelectedItemPosition());
+
+ double rate = speedConverter.getConversionRate(fromUnit.getSymbol(), toUnit.getSymbol());
+
+ String rateText = String.format("1 %s = %.4f %s",
+ fromUnit.getSymbol(), rate, toUnit.getSymbol());
+ speedRateText.setText(rateText);
+
+ } catch (Exception e) {
+ speedRateText.setText("Erro ao calcular taxa");
+ }
+ }
+}
+
diff --git a/app/src/main/java/com/example/conversordemoedas2/SpeedUnit.java b/app/src/main/java/com/example/conversordemoedas2/SpeedUnit.java
new file mode 100644
index 0000000..00cc629
--- /dev/null
+++ b/app/src/main/java/com/example/conversordemoedas2/SpeedUnit.java
@@ -0,0 +1,36 @@
+package com.example.conversordemoedas2;
+
+public class SpeedUnit {
+ private int id;
+ private String symbol;
+ private String name;
+ private double factorToMs;
+
+ public SpeedUnit(int id, String symbol, String name, double factorToMs) {
+ this.id = id;
+ this.symbol = symbol;
+ this.name = name;
+ this.factorToMs = factorToMs;
+ }
+
+ // Getters
+ public int getId() { return id; }
+ public String getSymbol() { return symbol; }
+ public String getName() { return name; }
+ public double getFactorToMs() { return factorToMs; }
+
+ // Setters
+ public void setId(int id) { this.id = id; }
+ public void setSymbol(String symbol) { this.symbol = symbol; }
+ public void setName(String name) { this.name = name; }
+ public void setFactorToMs(double factorToMs) { this.factorToMs = factorToMs; }
+
+ @Override
+ public String toString() {
+ return symbol + " - " + name;
+ }
+}
+
+
+
+
diff --git a/app/src/main/res/drawable/circle_background.xml b/app/src/main/res/drawable/circle_background.xml
new file mode 100644
index 0000000..4c17115
--- /dev/null
+++ b/app/src/main/res/drawable/circle_background.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/circle_background_speed.xml b/app/src/main/res/drawable/circle_background_speed.xml
new file mode 100644
index 0000000..e250c95
--- /dev/null
+++ b/app/src/main/res/drawable/circle_background_speed.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_arrow_back.xml b/app/src/main/res/drawable/ic_arrow_back.xml
new file mode 100644
index 0000000..04acb54
--- /dev/null
+++ b/app/src/main/res/drawable/ic_arrow_back.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..07d5da9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_foreground.xml b/app/src/main/res/drawable/ic_launcher_foreground.xml
new file mode 100644
index 0000000..2b068d1
--- /dev/null
+++ b/app/src/main/res/drawable/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_swap.xml b/app/src/main/res/drawable/ic_swap.xml
new file mode 100644
index 0000000..5e30b65
--- /dev/null
+++ b/app/src/main/res/drawable/ic_swap.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/spinner_background.xml b/app/src/main/res/drawable/spinner_background.xml
new file mode 100644
index 0000000..fbc31d5
--- /dev/null
+++ b/app/src/main/res/drawable/spinner_background.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..53bbb53
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,338 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_measurement_converter.xml b/app/src/main/res/layout/fragment_measurement_converter.xml
new file mode 100644
index 0000000..5b2cf9d
--- /dev/null
+++ b/app/src/main/res/layout/fragment_measurement_converter.xml
@@ -0,0 +1,214 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_speed_converter.xml b/app/src/main/res/layout/fragment_speed_converter.xml
new file mode 100644
index 0000000..6b52980
--- /dev/null
+++ b/app/src/main/res/layout/fragment_speed_converter.xml
@@ -0,0 +1,300 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..6f3b755
--- /dev/null
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/app/src/main/res/mipmap-hdpi/ic_launcher.webp
new file mode 100644
index 0000000..c209e78
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..b2dfe3d
Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/app/src/main/res/mipmap-mdpi/ic_launcher.webp
new file mode 100644
index 0000000..4f0f1d6
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..62b611d
Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
new file mode 100644
index 0000000..948a307
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..1b9a695
Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..28d4b77
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9287f50
Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
new file mode 100644
index 0000000..aa7d642
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
new file mode 100644
index 0000000..9126ae3
Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ
diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml
new file mode 100644
index 0000000..5efe0de
--- /dev/null
+++ b/app/src/main/res/values-night/themes.xml
@@ -0,0 +1,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
new file mode 100644
index 0000000..e533e8a
--- /dev/null
+++ b/app/src/main/res/values/colors.xml
@@ -0,0 +1,26 @@
+
+
+
+ #6366F1
+ #4F46E5
+ #10B981
+
+
+ #1F2937
+ #6B7280
+ #9CA3AF
+
+
+ #F8FAFC
+ #F3F4F6
+ #80FFFFFF
+
+
+ #10B981
+ #EF4444
+ #F59E0B
+
+
+ #FFFFFF
+ #000000
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..7b9ad89
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
+
+ conversordemoedas2
+
\ No newline at end of file
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
new file mode 100644
index 0000000..d184a51
--- /dev/null
+++ b/app/src/main/res/values/themes.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/backup_rules.xml b/app/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..4df9255
--- /dev/null
+++ b/app/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,13 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/data_extraction_rules.xml b/app/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..9ee9997
--- /dev/null
+++ b/app/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/test/java/com/example/conversordemoedas2/ExampleUnitTest.java b/app/src/test/java/com/example/conversordemoedas2/ExampleUnitTest.java
new file mode 100644
index 0000000..f2850b9
--- /dev/null
+++ b/app/src/test/java/com/example/conversordemoedas2/ExampleUnitTest.java
@@ -0,0 +1,17 @@
+package com.example.conversordemoedas2;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Example local unit test, which will execute on the development machine (host).
+ *
+ * @see Testing documentation
+ */
+public class ExampleUnitTest {
+ @Test
+ public void addition_isCorrect() {
+ assertEquals(4, 2 + 2);
+ }
+}
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
new file mode 100644
index 0000000..3756278
--- /dev/null
+++ b/build.gradle.kts
@@ -0,0 +1,4 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+plugins {
+ alias(libs.plugins.android.application) apply false
+}
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..7b54893
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,20 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
+org.gradle.daemon=true
+org.gradle.parallel=true
+org.gradle.configureondemand=true
+# AndroidX package structure to make it clearer which packages are bundled with the
+# Android operating system, and which are packaged with your app's APK
+# https://developer.android.com/topic/libraries/support-library/androidx-rn
+android.useAndroidX=true
+# Enables namespacing of each library's R class so that its R class includes only the
+# resources declared in the library itself and none from the library's dependencies,
+# thereby reducing the size of the R class for that library
+android.nonTransitiveRClass=true
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
new file mode 100644
index 0000000..bd926ff
--- /dev/null
+++ b/gradle/libs.versions.toml
@@ -0,0 +1,22 @@
+[versions]
+agp = "8.5.2"
+junit = "4.13.2"
+junitVersion = "1.2.0"
+espressoCore = "3.5.1"
+appcompat = "1.6.1"
+material = "1.11.0"
+activity = "1.8.2"
+constraintlayout = "2.1.4"
+
+[libraries]
+junit = { group = "junit", name = "junit", version.ref = "junit" }
+ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
+espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
+appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
+material = { group = "com.google.android.material", name = "material", version.ref = "material" }
+activity = { group = "androidx.activity", name = "activity", version.ref = "activity" }
+constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
+
+[plugins]
+android-application = { id = "com.android.application", version.ref = "agp" }
+
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..e644113
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..b82aa23
--- /dev/null
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,7 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
+networkTimeout=10000
+validateDistributionUrl=true
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..1aa94a4
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,249 @@
+#!/bin/sh
+
+#
+# Copyright © 2015-2021 the original authors.
+#
+# 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
+#
+# https://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.
+#
+
+##############################################################################
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
+##############################################################################
+
+# Attempt to set APP_HOME
+
+# Resolve links: $0 may be a link
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
+done
+
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
+APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD=maximum
+
+warn () {
+ echo "$*"
+} >&2
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+} >&2
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD=$JAVA_HOME/jre/sh/java
+ else
+ JAVACMD=$JAVA_HOME/bin/java
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD=java
+ if ! command -v java >/dev/null 2>&1
+ then
+ die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+fi
+
+# Increase the maximum file descriptors if we can.
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC2039,SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
+fi
+
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
+ fi
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
+ done
+fi
+
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Collect all arguments for the java command:
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
+# and any embedded shellness will be escaped.
+# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
+# treated as '${Hostname}' itself on the command line.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
+
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..7101f8e
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,92 @@
+@rem
+@rem Copyright 2015 the original author or authors.
+@rem
+@rem Licensed under the Apache License, Version 2.0 (the "License");
+@rem you may not use this file except in compliance with the License.
+@rem You may obtain a copy of the License at
+@rem
+@rem https://www.apache.org/licenses/LICENSE-2.0
+@rem
+@rem Unless required by applicable law or agreed to in writing, software
+@rem distributed under the License is distributed on an "AS IS" BASIS,
+@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+@rem See the License for the specific language governing permissions and
+@rem limitations under the License.
+@rem
+
+@if "%DEBUG%"=="" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Resolve any "." and ".." in APP_HOME to make it shorter.
+for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if %ERRORLEVEL% equ 0 goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto execute
+
+echo. 1>&2
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
+echo. 1>&2
+echo Please set the JAVA_HOME variable in your environment to match the 1>&2
+echo location of your Java installation. 1>&2
+
+goto fail
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
+
+:end
+@rem End local scope for the variables with windows NT shell
+if %ERRORLEVEL% equ 0 goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/settings.gradle.kts b/settings.gradle.kts
new file mode 100644
index 0000000..18a436e
--- /dev/null
+++ b/settings.gradle.kts
@@ -0,0 +1,24 @@
+pluginManagement {
+ repositories {
+ google {
+ content {
+ includeGroupByRegex("com\\.android.*")
+ includeGroupByRegex("com\\.google.*")
+ includeGroupByRegex("androidx.*")
+ }
+ }
+ mavenCentral()
+ gradlePluginPortal()
+ }
+}
+dependencyResolutionManagement {
+ repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
+ repositories {
+ google()
+ mavenCentral()
+ }
+}
+
+rootProject.name = "conversordemoedas2"
+include(":app")
+
\ No newline at end of file