Compare commits

...

44 Commits

Author SHA1 Message Date
894c9a845c adicao de jogadores na app 2026-02-26 09:58:16 +00:00
337440eb91 alteracoes precisas na app 2026-02-24 17:17:47 +00:00
421ba7c2e2 correcao de erros 2026-02-03 16:48:28 +00:00
2087572fa9 correcao de erros 2026-02-03 16:33:41 +00:00
e797216506 mudancas design 2026-01-29 10:37:46 +00:00
695e8cac2e imagem dos clubes inseridas 2026-01-29 10:30:59 +00:00
beede716c6 mudanca design 2026-01-28 10:09:22 +00:00
e2c3d0badd mudancas no design 2026-01-28 10:06:56 +00:00
7e70721c6c tirei um botao que nao serve para nada 2026-01-28 10:03:08 +00:00
e1150b3bf0 mudança ecra de clubes 2026-01-28 09:58:04 +00:00
e7aa23bbec mudanca de logo 2026-01-28 09:25:25 +00:00
2d27e4a227 mudanca logo 2026-01-28 09:20:09 +00:00
24acb90d58 mudanca de logo 2026-01-28 08:58:12 +00:00
371a298636 Correção da lista de clubes e jogadores 2026-01-27 17:12:17 +00:00
cd527224bf correcao 2026-01-23 16:36:17 +00:00
214d51d36e correcao 2026-01-23 16:29:12 +00:00
750e91538c mudancas para por a base de dados das equipas 2026-01-23 16:23:06 +00:00
f034364a41 alteracoes 2026-01-21 10:39:29 +00:00
a70395f258 mudanca visual 2026-01-20 17:11:20 +00:00
1dbbcb9a78 mudanca n visual 2026-01-20 17:08:19 +00:00
47a436c97d alteracoes design 2026-01-20 17:01:20 +00:00
66746a459a mudancas de visual 2026-01-20 16:57:44 +00:00
e06b4be7bf correcao de erros 2026-01-20 16:49:43 +00:00
6618e27afe alteracoes design de login e criar conta 2026-01-20 16:41:03 +00:00
ae62000ff3 refactor: Update settings UI to use color resources and refine MaterialCardView styling. 2026-01-20 15:49:42 +00:00
62d2a6bb51 mudanca de visual 2026-01-20 15:40:14 +00:00
fc4f786739 mudanças visual do app 2026-01-20 15:36:49 +00:00
ca26b8e146 correcao de erros 2026-01-20 14:57:35 +00:00
b297ff0e6e ver jogos ao vivo e ver os clubes 2026-01-20 14:53:21 +00:00
2e47ced7c7 alteraçoes 2025-12-12 10:40:22 +00:00
fe0dbed813 testessssss 2025-12-12 10:08:59 +00:00
f2ece221b6 teste 2025-12-12 10:07:25 +00:00
743ddeb3db mudanças 2025-12-12 09:28:14 +00:00
85a1907ef8 mudanças 2025-12-12 09:27:49 +00:00
2d4d229eac mudanças 2025-12-12 09:27:25 +00:00
4b766067f4 melhoramento da app 2025-12-06 22:26:42 +00:00
460b719785 adicao de botao de terminar sessao 2025-12-06 22:04:01 +00:00
81eb71bd46 Atualizar LoginActivity e ContaActivity 2025-12-06 21:47:50 +00:00
49ba834e96 correcao de coisas 2025-12-06 21:29:38 +00:00
4d80a9a27d correcao de erros 2025-12-06 21:13:22 +00:00
9875c82e65 correçao de erros no ecra da conta 2025-12-06 20:50:17 +00:00
66d019d9b6 Atualização das telas de login e conta + melhorias de layout 2025-12-05 00:05:43 +00:00
57056bbd6e correção de erros 2025-12-04 23:43:51 +00:00
f8cc655f74 melhorias 2025-12-03 21:44:55 +00:00
106 changed files with 4622 additions and 677 deletions

View File

@@ -4,14 +4,6 @@
<selectionStates>
<SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-11-26T09:17:18.598825Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="LocalEmulator" identifier="path=/Users/230421/.android/avd/Medium_Phone.avd" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState>
</selectionStates>
</component>

7
.idea/misc.xml generated
View File

@@ -6,4 +6,11 @@
<component name="ProjectType">
<option name="id" value="Android" />
</component>
<component name="VisualizationToolProject">
<option name="state">
<ProjectState>
<option name="scale" value="0.2492626953125" />
</ProjectState>
</option>
</component>
</project>

View File

@@ -46,6 +46,7 @@ dependencies {
implementation(libs.credentials.play.services.auth)
implementation(libs.googleid)
implementation(libs.firebase.database)
implementation(libs.firebase.storage)
implementation(libs.lifecycle.livedata.ktx)
implementation(libs.lifecycle.viewmodel.ktx)
implementation(libs.navigation.fragment)
@@ -53,4 +54,5 @@ dependencies {
testImplementation(libs.junit)
androidTestImplementation(libs.ext.junit)
androidTestImplementation(libs.espresso.core)
implementation("com.github.bumptech.glide:glide:4.16.0")
}

View File

@@ -1,6 +1,7 @@
{
"project_info": {
"project_number": "89853204936",
"firebase_url": "https://vdcscore-default-rtdb.firebaseio.com",
"project_id": "vdcscore",
"storage_bucket": "vdcscore.firebasestorage.app"
},

View File

@@ -2,6 +2,11 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.CAMERA" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
@@ -32,7 +37,7 @@
</intent-filter>
</activity>
<activity
android:name=".RecuperarSenhaActivity"
android:name=".RecuperarPasswordActivity"
android:exported="false" />
</application>

View File

@@ -30,12 +30,13 @@ public class CriarContaActivity extends AppCompatActivity {
});
TextInputEditText editPassword2;
TextInputEditText editEmail;
TextInputEditText editUserName;
TextInputEditText editConfirmPassword;
Button btnCreateAccount;
TextView txtGoLogin;
editEmail = findViewById(R.id.editEmail);
editUserName = findViewById(R.id.editUserName);
editPassword2 = findViewById(R.id.editPassword2);
editConfirmPassword = findViewById(R.id.editConfirmPassword);
btnCreateAccount = findViewById(R.id.btnCreateAccount);
@@ -46,46 +47,50 @@ public class CriarContaActivity extends AppCompatActivity {
@Override
public void onClick(View v) {
String email = editEmail.getText().toString().trim();
String pass = editPassword2.getText().toString();
String conf = editConfirmPassword.getText().toString();
String userName = editUserName.getText().toString().trim();
String pass = editPassword2.getText().toString().trim();
String conf = editConfirmPassword.getText().toString().trim();
if (email.isEmpty() || pass.isEmpty() || conf.isEmpty()) {
if (email.isEmpty() || userName.isEmpty() || pass.isEmpty() || conf.isEmpty()) {
Toast.makeText(CriarContaActivity.this, "Preencha todos os campos!", Toast.LENGTH_SHORT).show();
return;
}
if (!android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
Toast.makeText(CriarContaActivity.this, "Por favor, insira um email válido", Toast.LENGTH_SHORT).show();
return;
}
if (pass.length() < 6) {
Toast.makeText(CriarContaActivity.this, "A senha deve ter pelo menos 6 caracteres", Toast.LENGTH_SHORT).show();
return;
}
if (!pass.equals(conf)) {
Toast.makeText(CriarContaActivity.this, "As passwords não coincidem!", Toast.LENGTH_SHORT).show();
return;
}
FirebaseAuth auth = FirebaseAuth.getInstance();
auth.createUserWithEmailAndPassword(email, pass).addOnCompleteListener(CriarContaActivity.this, task -> {
if (task.isSuccessful()) {
Toast.makeText(CriarContaActivity.this, "Conta criada com sucesso!", Toast.LENGTH_SHORT).show();
Intent intent= new Intent(CriarContaActivity.this, MainActivity.class);
startActivity(intent);
finish();
} else {
String errorMessage = task.getException().getMessage();
if (errorMessage != null && errorMessage.contains("email")) {
Toast.makeText(CriarContaActivity.this, "Este email já está em uso", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(CriarContaActivity.this, "Erro ao criar conta: " + errorMessage, Toast.LENGTH_SHORT).show();
}
}
auth.createUserWithEmailAndPassword(email, pass).addOnCompleteListener(CriarContaActivity.this,
task -> {
if (task.isSuccessful()) {
// Atualizar nome de utilizador
com.google.firebase.auth.FirebaseUser user = auth.getCurrentUser();
if (user != null) {
com.google.firebase.auth.UserProfileChangeRequest profileUpdates = new com.google.firebase.auth.UserProfileChangeRequest.Builder()
.setDisplayName(userName)
.build();
});
user.updateProfile(profileUpdates).addOnCompleteListener(updateTask -> {
Intent intent = new Intent(CriarContaActivity.this, MainActivity.class);
startActivity(intent);
finish();
});
} else {
Intent intent = new Intent(CriarContaActivity.this, MainActivity.class);
startActivity(intent);
finish();
}
} else {
String errorMessage = "Erro ao criar conta!";
if (task.getException() != null && task.getException().getMessage() != null) {
errorMessage = "Erro: " + task.getException().getMessage();
}
Toast.makeText(CriarContaActivity.this, errorMessage, Toast.LENGTH_LONG).show();
}
});
}
});

View File

@@ -1,8 +1,10 @@
package com.example.vdcscore;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;
import android.widget.Toast;
@@ -15,11 +17,17 @@ public class LoginActivity extends AppCompatActivity {
TextInputEditText editEmail, editPassword;
Button btnLogin;
CheckBox checkRememberMe;
FirebaseAuth mAuth;
private TextView criarContaTextView;
private TextView txtForgotPassword;
private static final String PREFS_NAME = "LoginPrefs";
private static final String KEY_EMAIL = "email";
private static final String KEY_PASSWORD = "password";
private static final String KEY_REMEMBER = "remember";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -28,6 +36,7 @@ public class LoginActivity extends AppCompatActivity {
editEmail = findViewById(R.id.editEmail);
editPassword = findViewById(R.id.editPassword2);
btnLogin = findViewById(R.id.btnLogin);
checkRememberMe = findViewById(R.id.checkRememberMe);
criarContaTextView = findViewById(R.id.txtRegister);
txtForgotPassword = findViewById(R.id.txtForgotPassword);
@@ -35,7 +44,46 @@ public class LoginActivity extends AppCompatActivity {
btnLogin.setOnClickListener(v -> loginUser());
criarContaTextView.setOnClickListener(view -> criarConta());
txtForgotPassword.setOnClickListener(view -> recuperarSenha());
txtForgotPassword.setOnClickListener(view -> recuperarPassword());
// Carregar credenciais guardadas
loadSavedCredentials();
}
private void loadSavedCredentials() {
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
boolean remember = prefs.getBoolean(KEY_REMEMBER, false);
if (remember) {
String savedEmail = prefs.getString(KEY_EMAIL, "");
String savedPassword = prefs.getString(KEY_PASSWORD, "");
if (!savedEmail.isEmpty() && !savedPassword.isEmpty()) {
editEmail.setText(savedEmail);
editPassword.setText(savedPassword);
checkRememberMe.setChecked(true);
// Tentar login automático
autoLogin(savedEmail, savedPassword);
}
}
}
private void autoLogin(String email, String password) {
mAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
// Login automático bem-sucedido
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
} else {
// Se o login automático falhar, apenas limpar a password do campo
// O utilizador pode tentar fazer login manualmente
editPassword.setText("");
}
});
}
private void criarConta() {
@@ -43,8 +91,8 @@ public class LoginActivity extends AppCompatActivity {
startActivity(intent);
}
private void recuperarSenha() {
Intent intent = new Intent(LoginActivity.this, RecuperarSenhaActivity.class);
private void recuperarPassword() {
Intent intent = new Intent(LoginActivity.this, RecuperarPasswordActivity.class);
startActivity(intent);
}
@@ -57,42 +105,59 @@ public class LoginActivity extends AppCompatActivity {
return;
}
if (!android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
Toast.makeText(this, "Por favor, insira um email válido", Toast.LENGTH_SHORT).show();
return;
}
mAuth.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
// Guardar credenciais se "Lembrar-me" estiver marcado
if (checkRememberMe.isChecked()) {
saveCredentials(email, password);
} else {
clearSavedCredentials();
}
Toast.makeText(this, "Login efetuado!", Toast.LENGTH_SHORT).show();
// Abre a tua página principal
startActivity(new Intent(LoginActivity.this, MainActivity.class));
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
} else {
String errorMessage = task.getException().getMessage();
if (errorMessage != null && errorMessage.contains("password")) {
Toast.makeText(this,
"Senha incorreta. Esqueceu a senha?",
Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this,
"Erro: " + errorMessage,
Toast.LENGTH_LONG).show();
String errorMessage = "Erro ao fazer login!";
if (task.getException() != null && task.getException().getMessage() != null) {
errorMessage = "Erro: " + task.getException().getMessage();
}
Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show();
}
});
}
private void saveCredentials(String email, String password) {
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(KEY_EMAIL, email);
editor.putString(KEY_PASSWORD, password);
editor.putBoolean(KEY_REMEMBER, true);
editor.apply();
}
private void clearSavedCredentials() {
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.clear();
editor.apply();
}
@Override
protected void onStart() {
super.onStart();
// Verificar se já está autenticado (caso o login automático não tenha funcionado)
if (FirebaseAuth.getInstance().getCurrentUser() != null){
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
}
}
}

View File

@@ -1,8 +1,12 @@
package com.example.vdcscore;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.view.Menu;
import android.widget.ImageView;
import android.widget.TextView;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.navigation.NavigationView;
@@ -15,45 +19,203 @@ import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.app.AppCompatActivity;
import com.example.vdcscore.databinding.ActivityMainBinding;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import java.io.InputStream;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.net.Uri;
import android.text.InputType;
import android.widget.EditText;
import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.UploadTask;
import com.google.firebase.auth.UserProfileChangeRequest;
public class MainActivity extends AppCompatActivity {
private AppBarConfiguration mAppBarConfiguration;
private ActivityMainBinding binding;
private ActivityResultLauncher<String> mGetContent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Carregar preferência do Dark Mode
android.content.SharedPreferences prefs = getSharedPreferences("SettingsPrefs",
android.content.Context.MODE_PRIVATE);
boolean isDarkMode = prefs.getBoolean("dark_mode", false);
if (isDarkMode) {
androidx.appcompat.app.AppCompatDelegate
.setDefaultNightMode(androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES);
} else {
androidx.appcompat.app.AppCompatDelegate
.setDefaultNightMode(androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO);
}
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.appBarMain.toolbar);
binding.appBarMain.fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null)
.setAnchorView(R.id.fab).show();
}
});
DrawerLayout drawer = binding.drawerLayout;
NavigationView navigationView = binding.navView;
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
mAppBarConfiguration = new AppBarConfiguration.Builder(
R.id.nav_home, R.id.nav_gallery, R.id.nav_definicoes)
R.id.nav_home, R.id.nav_gallery, R.id.nav_definicoes,
R.id.nav_live_games, R.id.nav_clubs)
.setOpenableLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
// Initialize Gallery Launcher
mGetContent = registerForActivityResult(new ActivityResultContracts.GetContent(),
uri -> {
if (uri != null) {
uploadImageToStorage(uri);
}
});
// Carregar dados do utilizador no menu lateral
loadUserDataInNavHeader();
}
private void loadUserDataInNavHeader() {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user == null)
return;
View headerView = binding.navView.getHeaderView(0);
TextView textViewName = headerView.findViewById(R.id.textViewName);
ImageView imageView = headerView.findViewById(R.id.imageView);
// Carregar nome
if (textViewName != null) {
if (user.getDisplayName() != null && !user.getDisplayName().isEmpty()) {
textViewName.setText(user.getDisplayName());
} else {
textViewName.setText("Utilizador");
}
}
// Carregar foto de perfil
if (imageView != null) {
imageView.setOnClickListener(v -> showChangeProfilePhotoDialog());
if (user.getPhotoUrl() != null) {
loadProfileImageInNavHeader(user.getPhotoUrl().toString(), imageView);
} else {
// Tentar carregar do Storage
loadProfileImageFromStorage(imageView);
}
}
}
private void loadProfileImageInNavHeader(String imageUrl, ImageView imageView) {
new Thread(() -> {
InputStream input = null;
try {
java.net.URL url = new java.net.URL(imageUrl);
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
input = connection.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(input);
runOnUiThread(() -> {
if (bitmap != null && imageView != null) {
imageView.setImageBitmap(bitmap);
imageView.setScaleType(android.widget.ImageView.ScaleType.CENTER_CROP);
}
});
} catch (Exception e) {
// Se falhar, tentar carregar do Storage
runOnUiThread(() -> loadProfileImageFromStorage(imageView));
} finally {
if (input != null) {
try {
input.close();
} catch (Exception e) {
// Ignorar erro ao fechar
}
}
}
}).start();
}
private void loadProfileImageFromStorage(ImageView imageView) {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user == null || imageView == null)
return;
com.google.firebase.storage.FirebaseStorage.getInstance()
.getReference()
.child("profile_images/" + user.getUid() + ".jpg")
.getDownloadUrl()
.addOnSuccessListener(uri -> {
loadProfileImageInNavHeader(uri.toString(), imageView);
})
.addOnFailureListener(e -> {
// Manter imagem padrão
});
}
private void showChangeProfilePhotoDialog() {
mGetContent.launch("image/*");
}
private void uploadImageToStorage(Uri imageUri) {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user == null)
return;
StorageReference storageRef = com.google.firebase.storage.FirebaseStorage.getInstance().getReference();
StorageReference profileRef = storageRef.child("profile_images/" + user.getUid() + ".jpg");
Toast.makeText(this, "A carregar imagem...", Toast.LENGTH_SHORT).show();
profileRef.putFile(imageUri)
.addOnSuccessListener(taskSnapshot -> {
profileRef.getDownloadUrl().addOnSuccessListener(uri -> {
updateUserProfile(uri);
});
})
.addOnFailureListener(e -> {
Toast.makeText(MainActivity.this, "Erro ao carregar imagem: " + e.getMessage(), Toast.LENGTH_SHORT)
.show();
});
}
private void updateUserProfile(Uri photoUri) {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
if (user == null)
return;
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setPhotoUri(photoUri)
.build();
user.updateProfile(profileUpdates)
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
Toast.makeText(MainActivity.this, "Foto de perfil atualizada!", Toast.LENGTH_SHORT).show();
loadUserDataInNavHeader(); // Refresh UI
} else {
Toast.makeText(MainActivity.this, "Erro ao atualizar perfil.", Toast.LENGTH_SHORT).show();
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
// getMenuInflater().inflate(R.menu.main, menu);
// getMenuInflater().inflate(R.menu.main, menu);
return false;
}
@@ -63,4 +225,11 @@ public class MainActivity extends AppCompatActivity {
return NavigationUI.navigateUp(navController, mAppBarConfiguration)
|| super.onSupportNavigateUp();
}
@Override
protected void onResume() {
super.onResume();
// Atualizar dados do utilizador quando voltar à activity
loadUserDataInNavHeader();
}
}

View File

@@ -0,0 +1,77 @@
package com.example.vdcscore;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.textfield.TextInputEditText;
import com.google.firebase.auth.FirebaseAuth;
public class RecuperarPasswordActivity extends AppCompatActivity {
private TextInputEditText editEmailRecuperar;
private Button btnRecuperar;
private ImageButton btnBack;
private TextView txtVoltarLogin;
private FirebaseAuth mAuth;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recuperar_password);
editEmailRecuperar = findViewById(R.id.editEmailRecuperar);
btnRecuperar = findViewById(R.id.btnRecuperar);
btnBack = findViewById(R.id.btnBack);
txtVoltarLogin = findViewById(R.id.txtVoltarLogin);
mAuth = FirebaseAuth.getInstance();
btnRecuperar.setOnClickListener(v -> recuperarPassword());
btnBack.setOnClickListener(v -> voltarLogin());
txtVoltarLogin.setOnClickListener(v -> voltarLogin());
}
private void recuperarPassword() {
String email = editEmailRecuperar.getText().toString().trim();
if (email.isEmpty()) {
Toast.makeText(this, "Por favor, introduza o seu email", Toast.LENGTH_SHORT).show();
return;
}
if (!android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
Toast.makeText(this, "Por favor, introduza um email válido", Toast.LENGTH_SHORT).show();
return;
}
mAuth.sendPasswordResetEmail(email)
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
Toast.makeText(this,
"Email de recuperação enviado! Verifique a sua caixa de entrada.",
Toast.LENGTH_LONG).show();
voltarLogin();
} else {
String errorMessage = "Erro ao enviar email de recuperação!";
if (task.getException() != null && task.getException().getMessage() != null) {
errorMessage = "Erro: " + task.getException().getMessage();
}
Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show();
}
});
}
private void voltarLogin() {
Intent intent = new Intent(RecuperarPasswordActivity.this, LoginActivity.class);
startActivity(intent);
finish();
}
}

View File

@@ -1,72 +0,0 @@
package com.example.vdcscore;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.material.textfield.TextInputEditText;
import com.google.firebase.auth.FirebaseAuth;
public class RecuperarSenhaActivity extends AppCompatActivity {
private TextInputEditText editEmailRecover;
private Button btnSendRecovery;
private TextView txtBackToLogin;
private FirebaseAuth mAuth;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recuperar_senha);
editEmailRecover = findViewById(R.id.editEmailRecover);
btnSendRecovery = findViewById(R.id.btnSendRecovery);
txtBackToLogin = findViewById(R.id.txtBackToLogin);
mAuth = FirebaseAuth.getInstance();
btnSendRecovery.setOnClickListener(v -> sendRecoveryEmail());
txtBackToLogin.setOnClickListener(v -> backToLogin());
}
private void sendRecoveryEmail() {
String email = editEmailRecover.getText().toString().trim();
if (email.isEmpty()) {
Toast.makeText(this, "Por favor, insira o seu email", Toast.LENGTH_SHORT).show();
return;
}
if (!android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches()) {
Toast.makeText(this, "Por favor, insira um email válido", Toast.LENGTH_SHORT).show();
return;
}
mAuth.sendPasswordResetEmail(email)
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
Toast.makeText(this,
"Email de recuperação enviado! Verifique a sua caixa de entrada.",
Toast.LENGTH_LONG).show();
// Voltar ao login após enviar
backToLogin();
} else {
Toast.makeText(this,
"Erro: " + task.getException().getMessage(),
Toast.LENGTH_LONG).show();
}
});
}
private void backToLogin() {
Intent intent = new Intent(RecuperarSenhaActivity.this, LoginActivity.class);
startActivity(intent);
finish();
}
}

View File

@@ -0,0 +1,104 @@
package com.example.vdcscore.data;
import androidx.annotation.NonNull;
import com.example.vdcscore.models.Club;
import com.example.vdcscore.models.Jornada;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.ArrayList;
import java.util.List;
public class FirebaseRepository {
private final DatabaseReference mDatabase;
private static FirebaseRepository instance;
private FirebaseRepository() {
mDatabase = FirebaseDatabase.getInstance().getReference();
}
public static synchronized FirebaseRepository getInstance() {
if (instance == null) {
instance = new FirebaseRepository();
}
return instance;
}
// --- Clubs ---
public void addClub(Club club, OnCompleteListener<Void> onCompleteListener) {
String key = String.valueOf(club.getId());
if (key == null || key.isEmpty()) {
key = mDatabase.child("clubs").push().getKey();
club.setId(Integer.parseInt(key));
}
mDatabase.child("clubs").child(key).setValue(club).addOnCompleteListener(onCompleteListener);
}
public void getClubs(final DataCallback<List<Club>> callback) {
mDatabase.child("clubs").addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
List<Club> clubs = new ArrayList<>();
for (DataSnapshot postSnapshot : snapshot.getChildren()) {
Club club = postSnapshot.getValue(Club.class);
if (club != null) {
club.setId(Integer.parseInt(postSnapshot.getKey()));
clubs.add(club);
}
}
callback.onSuccess(clubs);
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
callback.onFailure(error.toException());
}
});
}
// --- Jornadas ---
public void addJornada(Jornada jornada, OnCompleteListener<Void> onCompleteListener) {
String key = jornada.getId();
if (key == null || key.isEmpty()) {
key = mDatabase.child("jornadas").push().getKey();
jornada.setId(key);
}
mDatabase.child("jornadas").child(key).setValue(jornada).addOnCompleteListener(onCompleteListener);
}
public void getJornadas(final DataCallback<List<Jornada>> callback) {
mDatabase.child("jornadas").addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
List<Jornada> jornadas = new ArrayList<>();
for (DataSnapshot postSnapshot : snapshot.getChildren()) {
Jornada jornada = postSnapshot.getValue(Jornada.class);
if (jornada != null) {
jornada.setId(postSnapshot.getKey());
jornadas.add(jornada);
}
}
callback.onSuccess(jornadas);
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
callback.onFailure(error.toException());
}
});
}
public interface DataCallback<T> {
void onSuccess(T data);
void onFailure(Exception e);
}
}

View File

@@ -0,0 +1,136 @@
package com.example.vdcscore.models;
import com.google.firebase.database.PropertyName;
import java.util.ArrayList;
import java.io.Serializable;
import java.util.List;
public class Club implements Serializable {
@PropertyName("id")
private int id;
@PropertyName("nome")
private String name;
@PropertyName("imagem")
private String imageUrl;
@PropertyName("campo")
private String stadium;
@PropertyName("ano fundacao")
private int foundationYear;
@PropertyName("morada")
private String address;
@PropertyName("presidente")
private String president;
@PropertyName("jogadores")
private ArrayList<Player> players;
public Club() {
// Default constructor for Firebase
players = new ArrayList<>();
}
public Club(int id, String name, String imageUrl, String stadium, int foundationYear, String address,
String president) {
this.id = id;
this.name = name;
this.imageUrl = imageUrl;
this.stadium = stadium;
this.foundationYear = foundationYear;
this.address = address;
this.president = president;
this.players = new ArrayList<>();
}
@PropertyName("id")
public int getId() {
return id;
}
@PropertyName("id")
public void setId(int id) {
this.id = id;
}
@PropertyName("nome")
public String getName() {
return name;
}
@PropertyName("nome")
public void setName(String name) {
this.name = name;
}
@PropertyName("imagem")
public String getImageUrl() {
return imageUrl;
}
@PropertyName("imagem")
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
@PropertyName("campo")
public String getStadium() {
return stadium;
}
@PropertyName("campo")
public void setStadium(String stadium) {
this.stadium = stadium;
}
@PropertyName("ano fundacao")
public int getFoundationYear() {
return foundationYear;
}
@PropertyName("ano fundacao")
public void setFoundationYear(int foundationYear) {
this.foundationYear = foundationYear;
}
@PropertyName("morada")
public String getAddress() {
return address;
}
@PropertyName("morada")
public void setAddress(String address) {
this.address = address;
}
@PropertyName("presidente")
public String getPresident() {
return president;
}
@PropertyName("presidente")
public void setPresident(String president) {
this.president = president;
}
@PropertyName("jogadores")
public ArrayList<Player> getPlayersMap() {
return players;
}
@PropertyName("jogadores")
public void setPlayersMap(ArrayList<Player> players) {
this.players = players;
}
public List<Player> getPlayersList() {
if (players == null)
return new ArrayList<>();
return new ArrayList<>(players);
}
}

View File

@@ -0,0 +1,102 @@
package com.example.vdcscore.models;
public class Game {
private String id;
private String homeTeamId;
private String awayTeamId;
private String homeTeamName;
private String awayTeamName;
private int homeScore;
private int awayScore;
private boolean isFinished;
private long timestamp;
public Game() {
// Required for Firebase
}
public Game(String id, String homeTeamId, String awayTeamId, String homeTeamName, String awayTeamName,
long timestamp) {
this.id = id;
this.homeTeamId = homeTeamId;
this.awayTeamId = awayTeamId;
this.homeTeamName = homeTeamName;
this.awayTeamName = awayTeamName;
this.timestamp = timestamp;
this.isFinished = false;
this.homeScore = 0;
this.awayScore = 0;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getHomeTeamId() {
return homeTeamId;
}
public void setHomeTeamId(String homeTeamId) {
this.homeTeamId = homeTeamId;
}
public String getAwayTeamId() {
return awayTeamId;
}
public void setAwayTeamId(String awayTeamId) {
this.awayTeamId = awayTeamId;
}
public String getHomeTeamName() {
return homeTeamName;
}
public void setHomeTeamName(String homeTeamName) {
this.homeTeamName = homeTeamName;
}
public String getAwayTeamName() {
return awayTeamName;
}
public void setAwayTeamName(String awayTeamName) {
this.awayTeamName = awayTeamName;
}
public int getHomeScore() {
return homeScore;
}
public void setHomeScore(int homeScore) {
this.homeScore = homeScore;
}
public int getAwayScore() {
return awayScore;
}
public void setAwayScore(int awayScore) {
this.awayScore = awayScore;
}
public boolean isFinished() {
return isFinished;
}
public void setFinished(boolean finished) {
isFinished = finished;
}
public long getTimestamp() {
return timestamp;
}
public void setTimestamp(long timestamp) {
this.timestamp = timestamp;
}
}

View File

@@ -0,0 +1,55 @@
package com.example.vdcscore.models;
import java.util.ArrayList;
import java.util.List;
public class Jornada {
private String id;
private int number;
private List<Game> games;
private boolean isCurrent;
public Jornada() {
// Required for Firebase
this.games = new ArrayList<>();
}
public Jornada(String id, int number) {
this.id = id;
this.number = number;
this.games = new ArrayList<>();
this.isCurrent = false;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public List<Game> getGames() {
return games;
}
public void setGames(List<Game> games) {
this.games = games;
}
public boolean isCurrent() {
return isCurrent;
}
public void setCurrent(boolean current) {
isCurrent = current;
}
}

View File

@@ -0,0 +1,40 @@
package com.example.vdcscore.models;
import com.google.firebase.database.PropertyName;
public class Player {
@PropertyName("id")
private int id;
@PropertyName("nome")
private String nome;
public Player() {
// Default constructor required for calls to DataSnapshot.getValue(Player.class)
}
public Player(int id, String nome) {
this.id = id;
this.nome = nome;
}
@PropertyName("id")
public int getId() {
return id;
}
@PropertyName("id")
public void setId(int id) {
this.id = id;
}
@PropertyName("nome")
public String getNome() {
return nome;
}
@PropertyName("nome")
public void setNome(String nome) {
this.nome = nome;
}
}

View File

@@ -0,0 +1,74 @@
package com.example.vdcscore.ui.clubs;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.example.vdcscore.R;
import com.example.vdcscore.models.Club;
import java.util.List;
public class ClubAdapter extends RecyclerView.Adapter<ClubAdapter.ClubViewHolder> {
private final List<Club> mClubs;
private final OnItemClickListener mListener;
public interface OnItemClickListener {
void onItemClick(Club club);
}
public ClubAdapter(List<Club> clubs, OnItemClickListener listener) {
mClubs = clubs;
mListener = listener;
}
@NonNull
@Override
public ClubViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_club, parent, false);
return new ClubViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ClubViewHolder holder, int position) {
Club club = mClubs.get(position);
holder.bind(club, mListener);
}
@Override
public int getItemCount() {
return mClubs.size();
}
static class ClubViewHolder extends RecyclerView.ViewHolder {
private final TextView name;
private final TextView stadium;
private final ImageView image_detail_logo;
public ClubViewHolder(@NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.text_club_name);
stadium = itemView.findViewById(R.id.text_club_stadium);
image_detail_logo = itemView.findViewById(R.id.image_club_logo);
}
public void bind(final Club club, final OnItemClickListener listener) {
name.setText(club.getName());
stadium.setText(club.getStadium());
Glide.with(itemView.getContext())
.load(club.getImageUrl())
.into(image_detail_logo);
itemView.setOnClickListener(v -> listener.onItemClick(club));
}
}
}

View File

@@ -0,0 +1,125 @@
package com.example.vdcscore.ui.clubs;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.navigation.Navigation;
import com.example.vdcscore.R;
import com.example.vdcscore.databinding.FragmentClubDetailBinding;
import com.example.vdcscore.models.Club;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import com.bumptech.glide.Glide;
public class ClubDetailFragment extends Fragment {
private FragmentClubDetailBinding binding;
private DatabaseReference mDatabase;
private String clubId;
private String escalao;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
clubId = getArguments().getString("clubId");
escalao = getArguments().getString("escalao");
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
binding = FragmentClubDetailBinding.inflate(inflater, container, false);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (getArguments() != null) {
Club clubeRecebido = (Club) getArguments().getSerializable("clube_selecionado");
if (clubeRecebido != null) {
// Preencher views diretamente
binding.textDetailClubName.setText(clubeRecebido.getName());
binding.textDetailFoundation.setText(String.valueOf(clubeRecebido.getFoundationYear()));
binding.textDetailPresident.setText(clubeRecebido.getPresident());
binding.textDetailAddress.setText(clubeRecebido.getAddress());
if (getContext() != null) {
Glide.with(this)
.load(clubeRecebido.getImageUrl())
.placeholder(R.mipmap.ic_launcher_round)
.error(R.mipmap.ic_launcher)
.into(binding.imageDetailLogo);
}
// Configurar o botão para ver jogadores
binding.btnPlayers.setOnClickListener(v -> {
Bundle bundle = new Bundle();
// Passar o 'clube_selecionado' também para a lista de jogadores se necessário,
// ou passar o ID como antes se o fragmento de jogadores esperar ID
bundle.putString("clubId", String.valueOf(clubeRecebido.getId()));
bundle.putString("escalao", escalao);
// Se o ClubPlayersFragment esperar "clube_selecionado" tambem, poderiamos
// passar:
// bundle.putSerializable("clube_selecionado", clubeRecebido);
Navigation.findNavController(view).navigate(R.id.action_nav_club_detail_to_nav_club_players,
bundle);
});
}
}
}
private void loadClubDetails() {
mDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
Club club = snapshot.getValue(Club.class);
if (club != null) {
binding.textDetailClubName.setText(club.getName());
binding.textDetailFoundation.setText(String.valueOf(club.getFoundationYear()));
binding.textDetailPresident.setText(club.getPresident());
binding.textDetailAddress.setText(club.getAddress());
// binding.textDetailStadium.setText(club.getStadium()); // Hidden for now
// binding.imageDetailLogo.setImageResource(R.mipmap.ic_launcher_round);
if (getContext() != null) {
Glide.with(ClubDetailFragment.this)
.load(club.getImageUrl())
.placeholder(R.mipmap.ic_launcher_round)
.error(R.mipmap.ic_launcher)
.into(binding.imageDetailLogo);
}
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
if (getContext() != null) {
Toast.makeText(getContext(), "Failed to load club details.", Toast.LENGTH_SHORT).show();
}
}
});
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}

View File

@@ -0,0 +1,103 @@
package com.example.vdcscore.ui.clubs;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.example.vdcscore.databinding.FragmentClubPlayersBinding;
import com.example.vdcscore.models.Club;
import com.example.vdcscore.models.Player;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.ArrayList;
import java.util.List;
public class ClubPlayersFragment extends Fragment {
private FragmentClubPlayersBinding binding;
private DatabaseReference mDatabase;
private String clubId;
private String escalao;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
clubId = getArguments().getString("clubId");
escalao = getArguments().getString("escalao");
}
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
binding = FragmentClubPlayersBinding.inflate(inflater, container, false);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
binding.recyclerPlayersList.setLayoutManager(new LinearLayoutManager(getContext()));
binding.progressBarPlayers.setVisibility(View.VISIBLE);
if (clubId != null && escalao != null) {
mDatabase = FirebaseDatabase.getInstance().getReference().child("clubes").child(escalao).child(clubId);
loadPlayers();
} else {
binding.progressBarPlayers.setVisibility(View.GONE);
binding.textNoPlayers.setVisibility(View.VISIBLE);
binding.textNoPlayers.setText("Erro: Clube ou escalão não identificado.");
}
}
private void loadPlayers() {
mDatabase.addListenerForSingleValueEvent(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
Club club = snapshot.getValue(Club.class);
binding.progressBarPlayers.setVisibility(View.GONE);
if (club != null) {
List<Player> playerList = club.getPlayersList();
if (playerList != null && !playerList.isEmpty()) {
PlayerAdapter adapter = new PlayerAdapter(playerList);
binding.recyclerPlayersList.setAdapter(adapter);
binding.textNoPlayers.setVisibility(View.GONE);
} else {
binding.textNoPlayers.setVisibility(View.VISIBLE);
}
} else {
binding.textNoPlayers.setVisibility(View.VISIBLE);
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
if (getContext() != null) {
Toast.makeText(getContext(), "Failed to load players.", Toast.LENGTH_SHORT).show();
}
binding.progressBarPlayers.setVisibility(View.GONE);
}
});
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}

View File

@@ -0,0 +1,122 @@
package com.example.vdcscore.ui.clubs;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ProgressBar;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.navigation.Navigation;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.example.vdcscore.R;
import com.example.vdcscore.databinding.FragmentClubsBinding;
import com.example.vdcscore.models.Club;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.ArrayList;
import java.util.List;
public class ClubsFragment extends Fragment {
private FragmentClubsBinding binding;
private DatabaseReference mDatabase;
private ValueEventListener mValueEventListener;
private static final String TAG = "ClubsFragment";
private String currentEscalao = "seniores"; // Default selection
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
binding = FragmentClubsBinding.inflate(inflater, container, false);
View root = binding.getRoot();
RecyclerView recyclerView = binding.recyclerClubs;
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
ProgressBar progressBar = binding.progressBar;
// Set up toggle listener
binding.toggleGroupEscalao.addOnButtonCheckedListener((group, checkedId, isChecked) -> {
if (isChecked) {
if (checkedId == R.id.btnJuniores) {
currentEscalao = "juniores";
} else if (checkedId == R.id.btnSeniores) {
currentEscalao = "seniores";
}
loadClubsData(recyclerView, progressBar);
}
});
// Initial Data Load
loadClubsData(recyclerView, progressBar);
return root;
}
private void loadClubsData(RecyclerView recyclerView, ProgressBar progressBar) {
progressBar.setVisibility(View.VISIBLE);
mDatabase = FirebaseDatabase.getInstance().getReference().child("clubes").child(currentEscalao);
// Remove previous listener to avoid duplicate data or leaks
if (mValueEventListener != null) {
mDatabase.removeEventListener(mValueEventListener);
}
mValueEventListener = new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
List<Club> clubs = new ArrayList<>();
for (DataSnapshot postSnapshot : snapshot.getChildren()) {
Club club = postSnapshot.getValue(Club.class);
if (club != null) {
clubs.add(club);
}
}
ClubAdapter adapter = new ClubAdapter(clubs, club -> {
Bundle bundle = new Bundle();
bundle.putSerializable("clube_selecionado", club);
bundle.putString("escalao", currentEscalao);
androidx.navigation.fragment.NavHostFragment.findNavController(ClubsFragment.this)
.navigate(R.id.action_nav_clubs_to_nav_club_detail, bundle);
});
recyclerView.setAdapter(adapter);
progressBar.setVisibility(View.GONE);
if (clubs.isEmpty()) {
// Keep UI empty but don't show mock data automatically to avoid confusion
// Toast.makeText(getContext(), "No clubs found.", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
Log.w(TAG, "loadClubs:onCancelled", error.toException());
if (getContext() != null) {
Toast.makeText(getContext(), "Failed to load clubs.", Toast.LENGTH_SHORT).show();
}
if (binding != null) {
binding.progressBar.setVisibility(View.GONE);
}
}
};
mDatabase.addValueEventListener(mValueEventListener);
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (mDatabase != null && mValueEventListener != null) {
mDatabase.removeEventListener(mValueEventListener);
}
binding = null;
}
}

View File

@@ -0,0 +1,57 @@
package com.example.vdcscore.ui.clubs;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.vdcscore.R;
import com.example.vdcscore.models.Player;
import java.util.List;
public class PlayerAdapter extends RecyclerView.Adapter<PlayerAdapter.PlayerViewHolder> {
private final List<Player> mPlayers;
public PlayerAdapter(List<Player> players) {
mPlayers = players;
}
@NonNull
@Override
public PlayerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_player, parent, false);
return new PlayerViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull PlayerViewHolder holder, int position) {
Player player = mPlayers.get(position);
holder.bind(player);
}
@Override
public int getItemCount() {
return mPlayers.size();
}
static class PlayerViewHolder extends RecyclerView.ViewHolder {
private final TextView name;
public PlayerViewHolder(@NonNull View itemView) {
super(itemView);
name = itemView.findViewById(R.id.text_player_name);
}
public void bind(Player player) {
if (player != null){
name.setText(player.getNome());
}
}
}
}

View File

@@ -1,26 +1,491 @@
package com.example.vdcscore.ui.definicoes;
import android.Manifest;
import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.activity.EdgeToEdge;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import com.example.vdcscore.LoginActivity;
import com.example.vdcscore.R;
import com.google.android.material.appbar.MaterialToolbar;
import com.google.android.material.textfield.TextInputEditText;
import com.google.firebase.auth.FirebaseAuth;
import com.google.firebase.auth.FirebaseUser;
import com.google.firebase.auth.UserProfileChangeRequest;
import com.google.firebase.storage.FirebaseStorage;
import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.UploadTask;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
public class ContaActivity extends AppCompatActivity {
private ImageView imageProfile;
private TextInputEditText editName;
private TextView textEmail;
private Button btnSaveAll;
private Button btnChangeEmail;
private Button btnChangePassword;
private Button btnLogout;
private View btnChangePhoto;
private View cardImageContainer;
private FirebaseAuth mAuth;
private FirebaseStorage mStorage;
private StorageReference storageRef;
private ProgressDialog progressDialog;
private ActivityResultLauncher<Intent> imagePickerLauncher;
private ActivityResultLauncher<String> permissionLauncher;
private Uri selectedImageUri;
private static final String PREFS_NAME = "LoginPrefs";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
EdgeToEdge.enable(this);
setContentView(R.layout.activity_conta);
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;
});
// Inicializar componentes
initViews();
initFirebase();
setupImagePicker();
setupPermissionLauncher();
loadUserData();
setupListeners();
}
private void initViews() {
MaterialToolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (toolbar != null) {
toolbar.setNavigationOnClickListener(v -> finish());
}
imageProfile = findViewById(R.id.imageProfile);
editName = findViewById(R.id.editName);
// In XML it is present as @+id/textEmail inside cardSecurity.
textEmail = findViewById(R.id.textEmail);
btnSaveAll = findViewById(R.id.btnSaveAll);
btnChangeEmail = findViewById(R.id.btnChangeEmail);
btnChangePassword = findViewById(R.id.btnChangePassword);
btnLogout = findViewById(R.id.btnLogout);
// New FAB for editing photo
btnChangePhoto = findViewById(R.id.fabEditPhoto);
// Also allow clicking the text
View btnChangePhotoText = findViewById(R.id.btnChangePhoto);
cardImageContainer = findViewById(R.id.cardImageContainer);
progressDialog = new ProgressDialog(this);
progressDialog.setMessage("A processar...");
progressDialog.setCancelable(false);
// Setup listeners here or in setupListeners()
if (btnChangePhotoText != null) {
btnChangePhotoText.setOnClickListener(v -> openImagePicker());
}
}
private void initFirebase() {
mAuth = FirebaseAuth.getInstance();
mStorage = FirebaseStorage.getInstance();
storageRef = mStorage.getReference();
}
private void setupImagePicker() {
imagePickerLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == RESULT_OK && result.getData() != null) {
selectedImageUri = result.getData().getData();
if (selectedImageUri != null) {
try {
InputStream inputStream = getContentResolver().openInputStream(selectedImageUri);
if (inputStream != null) {
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
inputStream.close();
if (bitmap != null) {
imageProfile.setImageBitmap(bitmap);
// Não fazemos upload até clicar em Gravar
} else {
Toast.makeText(this, "Erro ao carregar imagem", Toast.LENGTH_SHORT).show();
}
}
} catch (Exception e) {
Toast.makeText(this, "Erro ao carregar imagem: " + e.getMessage(), Toast.LENGTH_SHORT)
.show();
}
}
}
});
}
private void setupPermissionLauncher() {
permissionLauncher = registerForActivityResult(
new ActivityResultContracts.RequestPermission(),
isGranted -> {
if (isGranted) {
openImagePicker();
} else {
Toast.makeText(this, "Permissão necessária para selecionar imagem", Toast.LENGTH_SHORT).show();
}
});
}
private void loadUserData() {
FirebaseUser user = mAuth.getCurrentUser();
if (user != null) {
// Carregar email
if (textEmail != null) {
textEmail.setText(user.getEmail() != null ? user.getEmail() : "");
}
// Carregar nome
if (editName != null && user.getDisplayName() != null && !user.getDisplayName().isEmpty()) {
editName.setText(user.getDisplayName());
}
// Carregar foto de perfil
if (user.getPhotoUrl() != null) {
loadProfileImage(user.getPhotoUrl().toString());
} else {
// Tentar carregar do Storage
loadProfileImageFromStorage();
}
} else {
Toast.makeText(this, "Utilizador não autenticado", Toast.LENGTH_SHORT).show();
finish();
}
}
private void loadProfileImage(String imageUrl) {
new Thread(() -> {
InputStream input = null;
try {
java.net.URL url = new java.net.URL(imageUrl);
java.net.HttpURLConnection connection = (java.net.HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.connect();
input = connection.getInputStream();
Bitmap bitmap = BitmapFactory.decodeStream(input);
runOnUiThread(() -> {
if (bitmap != null && imageProfile != null) {
imageProfile.setImageBitmap(bitmap);
}
});
} catch (Exception e) {
runOnUiThread(() -> loadProfileImageFromStorage());
} finally {
if (input != null) {
try {
input.close();
} catch (Exception e) {
// Ignorar erro ao fechar
}
}
}
}).start();
}
private void loadProfileImageFromStorage() {
FirebaseUser user = mAuth.getCurrentUser();
if (user == null)
return;
StorageReference profileImageRef = storageRef.child("profile_images/" + user.getUid() + ".jpg");
profileImageRef.getDownloadUrl().addOnSuccessListener(uri -> {
loadProfileImage(uri.toString());
}).addOnFailureListener(e -> {
// Foto não encontrada, manter imagem padrão
});
}
private void setupListeners() {
if (btnChangePhoto != null) {
btnChangePhoto.setOnClickListener(v -> openImagePicker());
}
if (cardImageContainer != null) {
cardImageContainer.setOnClickListener(v -> openImagePicker());
}
if (btnSaveAll != null) {
btnSaveAll.setOnClickListener(v -> saveAllChanges());
}
if (btnChangeEmail != null) {
btnChangeEmail.setOnClickListener(v -> sendEmailVerificationForEmailChange());
}
if (btnChangePassword != null) {
btnChangePassword.setOnClickListener(v -> sendPasswordResetEmail());
}
if (btnLogout != null) {
btnLogout.setOnClickListener(v -> showLogoutConfirmation());
}
}
private void openImagePicker() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
imagePickerLauncher.launch(intent);
} else {
String permission = Manifest.permission.READ_EXTERNAL_STORAGE;
if (ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED) {
Intent intent = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
imagePickerLauncher.launch(intent);
} else {
permissionLauncher.launch(permission);
}
}
}
private void saveAllChanges() {
if (editName == null)
return;
String newName = editName.getText().toString().trim();
if (newName.isEmpty() && selectedImageUri == null) {
Toast.makeText(this, "Nenhuma alteração a guardar", Toast.LENGTH_SHORT).show();
return;
}
FirebaseUser user = mAuth.getCurrentUser();
if (user == null) {
Toast.makeText(this, "Utilizador não autenticado", Toast.LENGTH_SHORT).show();
return;
}
progressDialog.show();
// Se tiver foto nova, primeiro faz upload
if (selectedImageUri != null) {
uploadNewProfileImageAndSaveName(user, newName);
} else {
// Só muda o nome
saveNameOnly(user, newName);
}
}
private void saveNameOnly(FirebaseUser user, String newName) {
if (newName.isEmpty()) {
progressDialog.dismiss();
return; // Se não houver nome para trocar nem imagem, já barrámos em saveAllChanges.
}
UserProfileChangeRequest profileUpdates = new UserProfileChangeRequest.Builder()
.setDisplayName(newName)
.build();
user.updateProfile(profileUpdates).addOnCompleteListener(task -> {
progressDialog.dismiss();
if (task.isSuccessful()) {
Toast.makeText(this, "Alterações guardadas com sucesso!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Erro ao guardar alterações: " +
(task.getException() != null ? task.getException().getMessage() : "Erro desconhecido"),
Toast.LENGTH_SHORT).show();
}
});
}
private void uploadNewProfileImageAndSaveName(FirebaseUser user, String newName) {
InputStream inputStream = null;
try {
inputStream = getContentResolver().openInputStream(selectedImageUri);
if (inputStream == null) {
progressDialog.dismiss();
Toast.makeText(this, "Erro ao abrir imagem", Toast.LENGTH_SHORT).show();
return;
}
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
if (bitmap == null) {
progressDialog.dismiss();
Toast.makeText(this, "Erro ao processar imagem", Toast.LENGTH_SHORT).show();
return;
}
// Redimensionar
int maxSize = 1024;
if (bitmap.getWidth() > maxSize || bitmap.getHeight() > maxSize) {
float scale = Math.min((float) maxSize / bitmap.getWidth(), (float) maxSize / bitmap.getHeight());
int newWidth = Math.round(bitmap.getWidth() * scale);
int newHeight = Math.round(bitmap.getHeight() * scale);
bitmap = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true);
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, baos);
byte[] imageData = baos.toByteArray();
StorageReference profileImageRef = storageRef.child("profile_images/" + user.getUid() + ".jpg");
UploadTask uploadTask = profileImageRef.putBytes(imageData);
uploadTask.addOnSuccessListener(taskSnapshot -> {
profileImageRef.getDownloadUrl().addOnSuccessListener(uri -> {
UserProfileChangeRequest.Builder builder = new UserProfileChangeRequest.Builder();
builder.setPhotoUri(uri);
if (!newName.isEmpty()) {
builder.setDisplayName(newName);
}
UserProfileChangeRequest profileUpdates = builder.build();
user.updateProfile(profileUpdates).addOnCompleteListener(task -> {
progressDialog.dismiss();
if (task.isSuccessful()) {
Toast.makeText(this, "As definições foram guardadas!", Toast.LENGTH_SHORT).show();
loadProfileImage(uri.toString());
selectedImageUri = null; // reset
} else {
Toast.makeText(this, "Erro ao atualizar perfil", Toast.LENGTH_SHORT).show();
}
});
}).addOnFailureListener(e -> {
progressDialog.dismiss();
Toast.makeText(this, "Erro ao obter URL: " + e.getMessage(), Toast.LENGTH_SHORT).show();
});
}).addOnFailureListener(e -> {
progressDialog.dismiss();
Toast.makeText(this, "Erro ao fazer upload: " + e.getMessage(), Toast.LENGTH_SHORT).show();
});
} catch (Exception e) {
progressDialog.dismiss();
Toast.makeText(this, "Erro: " + e.getMessage(), Toast.LENGTH_SHORT).show();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (Exception e) {
}
}
}
}
private void sendPasswordResetEmail() {
FirebaseUser user = mAuth.getCurrentUser();
if (user == null || user.getEmail() == null) {
Toast.makeText(this, "Utilizador não autenticado", Toast.LENGTH_SHORT).show();
return;
}
progressDialog.show();
mAuth.sendPasswordResetEmail(user.getEmail())
.addOnCompleteListener(task -> {
progressDialog.dismiss();
if (task.isSuccessful()) {
Toast.makeText(this,
"Email de alteração de password enviado! Verifique a sua caixa de entrada.",
Toast.LENGTH_LONG).show();
} else {
String errorMessage = "Erro ao enviar email!";
if (task.getException() != null && task.getException().getMessage() != null) {
errorMessage = "Erro: " + task.getException().getMessage();
}
Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show();
}
});
}
private void sendEmailVerificationForEmailChange() {
FirebaseUser user = mAuth.getCurrentUser();
if (user == null || user.getEmail() == null) {
Toast.makeText(this, "Utilizador não autenticado", Toast.LENGTH_SHORT).show();
return;
}
progressDialog.show();
// Enviar email de verificação para alterar email
user.sendEmailVerification()
.addOnCompleteListener(task -> {
progressDialog.dismiss();
if (task.isSuccessful()) {
Toast.makeText(this,
"Email de verificação enviado! Verifique a sua caixa de entrada para alterar o email.",
Toast.LENGTH_LONG).show();
} else {
// Se não conseguir enviar email de verificação, enviar email de reset de
// password
// que pode ser usado para alterar o email através do Firebase Console
mAuth.sendPasswordResetEmail(user.getEmail())
.addOnCompleteListener(resetTask -> {
if (resetTask.isSuccessful()) {
Toast.makeText(this,
"Email enviado! Verifique a sua caixa de entrada para instruções de alteração.",
Toast.LENGTH_LONG).show();
} else {
String errorMessage = "Erro ao enviar email!";
if (resetTask.getException() != null
&& resetTask.getException().getMessage() != null) {
errorMessage = "Erro: " + resetTask.getException().getMessage();
}
Toast.makeText(this, errorMessage, Toast.LENGTH_LONG).show();
}
});
}
});
}
private void showLogoutConfirmation() {
new AlertDialog.Builder(this)
.setTitle("Terminar Sessão")
.setMessage("Tem a certeza que deseja terminar a sessão?")
.setPositiveButton("Sim", (dialog, which) -> logoutUser())
.setNegativeButton("Cancelar", null)
.show();
}
private void logoutUser() {
// Limpar credenciais guardadas
SharedPreferences prefs = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
SharedPreferences.Editor editor = prefs.edit();
editor.clear();
editor.apply();
// Fazer logout do Firebase
mAuth.signOut();
Toast.makeText(this, "Sessão terminada", Toast.LENGTH_SHORT).show();
// Voltar para o login
Intent intent = new Intent(ContaActivity.this, LoginActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
finish();
}
}

View File

@@ -24,13 +24,14 @@ public class DefinicoesFragment extends Fragment {
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater,
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
binding = FragmentDefinicoesBinding.inflate(inflater, container, false);
setupUi();
return binding.getRoot();
}
//teste
// teste
private void setupUi() {
binding.cardConta.setOnClickListener(new View.OnClickListener() {
@Override
@@ -44,14 +45,35 @@ public class DefinicoesFragment extends Fragment {
}
});
binding.switchNotifications.setOnCheckedChangeListener((buttonView, isChecked) ->
binding.textNotificationsStatus.setText(
binding.switchNotifications
.setOnCheckedChangeListener((buttonView, isChecked) -> binding.textNotificationsStatus.setText(
isChecked ? "Ativadas" : "Desativadas"));
binding.switchDarkMode.setOnCheckedChangeListener((buttonView, isChecked) ->
binding.textDarkModeStatus.setText(
isChecked ? "Ativo" : "Inativo"));
// Obter SharedPreferences
android.content.SharedPreferences prefs = requireActivity().getSharedPreferences("SettingsPrefs",
android.content.Context.MODE_PRIVATE);
boolean isDarkMode = prefs.getBoolean("dark_mode", false);
binding.switchDarkMode.setChecked(isDarkMode);
binding.textDarkModeStatus.setText(isDarkMode ? "Ativo" : "Inativo");
binding.switchDarkMode.setOnCheckedChangeListener((buttonView, isChecked) -> {
binding.textDarkModeStatus.setText(isChecked ? "Ativo" : "Inativo");
// Guardar preferência
android.content.SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("dark_mode", isChecked);
editor.apply();
// Aplicar modo escuro
if (isChecked) {
androidx.appcompat.app.AppCompatDelegate
.setDefaultNightMode(androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_YES);
} else {
androidx.appcompat.app.AppCompatDelegate
.setDefaultNightMode(androidx.appcompat.app.AppCompatDelegate.MODE_NIGHT_NO);
}
});
binding.btnOpenSystemSettings.setOnClickListener(v -> {
Intent intent = new Intent(Settings.ACTION_SETTINGS);
@@ -66,4 +88,3 @@ public class DefinicoesFragment extends Fragment {
binding = null;
}
}

View File

@@ -4,31 +4,82 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.example.vdcscore.databinding.FragmentGalleryBinding;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.ArrayList;
import java.util.List;
public class GalleryFragment extends Fragment {
private FragmentGalleryBinding binding;
private MatchdaysAdapter adapter;
private DatabaseReference mDatabase;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
GalleryViewModel galleryViewModel =
new ViewModelProvider(this).get(GalleryViewModel.class);
ViewGroup container, Bundle savedInstanceState) {
binding = FragmentGalleryBinding.inflate(inflater, container, false);
View root = binding.getRoot();
final TextView textView = binding.textGallery;
galleryViewModel.getText().observe(getViewLifecycleOwner(), textView::setText);
// Initialize RecyclerView
adapter = new MatchdaysAdapter();
binding.recyclerMatchdays.setLayoutManager(new LinearLayoutManager(getContext()));
binding.recyclerMatchdays.setAdapter(adapter);
// Initialize Firebase
mDatabase = FirebaseDatabase.getInstance().getReference("matchdays");
// Fetch Data
fetchMatchdays();
return root;
}
private void fetchMatchdays() {
mDatabase.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
List<Matchday> matchdays = new ArrayList<>();
for (DataSnapshot postSnapshot : snapshot.getChildren()) {
Matchday matchday = new Matchday();
matchday.setId(postSnapshot.getKey());
matchday.setName(postSnapshot.child("name").getValue(String.class));
List<Match> matches = new ArrayList<>();
for (DataSnapshot matchSnapshot : postSnapshot.child("matches").getChildren()) {
Match match = matchSnapshot.getValue(Match.class);
if (match != null) {
match.setId(matchSnapshot.getKey());
matches.add(match);
}
}
matchday.setMatches(matches);
matchdays.add(matchday);
}
adapter.setMatchdays(matchdays);
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
if (getContext() != null) {
Toast.makeText(getContext(), "Erro ao carregar jornadas: " + error.getMessage(), Toast.LENGTH_SHORT)
.show();
}
}
});
}
@Override
public void onDestroyView() {
super.onDestroyView();

View File

@@ -0,0 +1,88 @@
package com.example.vdcscore.ui.gallery;
public class Match {
private String id;
private String homeTeam;
private String awayTeam;
private int homeScore;
private int awayScore;
private String date;
private String time;
private String status; // "Scheduled", "Finished", "Live"
public Match() {
}
public Match(String homeTeam, String awayTeam, String date, String time) {
this.homeTeam = homeTeam;
this.awayTeam = awayTeam;
this.date = date;
this.time = time;
this.status = "Scheduled";
}
// Getters and Setters
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getHomeTeam() {
return homeTeam;
}
public void setHomeTeam(String homeTeam) {
this.homeTeam = homeTeam;
}
public String getAwayTeam() {
return awayTeam;
}
public void setAwayTeam(String awayTeam) {
this.awayTeam = awayTeam;
}
public int getHomeScore() {
return homeScore;
}
public void setHomeScore(int homeScore) {
this.homeScore = homeScore;
}
public int getAwayScore() {
return awayScore;
}
public void setAwayScore(int awayScore) {
this.awayScore = awayScore;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
}

View File

@@ -0,0 +1,41 @@
package com.example.vdcscore.ui.gallery;
import java.util.List;
public class Matchday {
private String id;
private String name; // e.g., "Jornada 1"
private List<Match> matches;
public Matchday() {
}
public Matchday(String name, List<Match> matches) {
this.name = name;
this.matches = matches;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Match> getMatches() {
return matches;
}
public void setMatches(List<Match> matches) {
this.matches = matches;
}
}

View File

@@ -0,0 +1,68 @@
package com.example.vdcscore.ui.gallery;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.example.vdcscore.R;
import java.util.ArrayList;
import java.util.List;
public class MatchdaysAdapter extends RecyclerView.Adapter<MatchdaysAdapter.ViewHolder> {
private List<Matchday> matchdays = new ArrayList<>();
private RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool();
public void setMatchdays(List<Matchday> matchdays) {
this.matchdays = matchdays;
notifyDataSetChanged();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_matchday, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Matchday matchday = matchdays.get(position);
holder.textName.setText(matchday.getName());
// Setup nested RecyclerView
LinearLayoutManager layoutManager = new LinearLayoutManager(
holder.recyclerMatches.getContext(),
LinearLayoutManager.VERTICAL,
false);
layoutManager.setInitialPrefetchItemCount(matchday.getMatches().size());
MatchesAdapter matchesAdapter = new MatchesAdapter(matchday.getMatches());
holder.recyclerMatches.setLayoutManager(layoutManager);
holder.recyclerMatches.setAdapter(matchesAdapter);
holder.recyclerMatches.setRecycledViewPool(viewPool);
}
@Override
public int getItemCount() {
return matchdays.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public final TextView textName;
public final RecyclerView recyclerMatches;
public ViewHolder(View view) {
super(view);
textName = view.findViewById(R.id.text_matchday_name);
recyclerMatches = view.findViewById(R.id.recycler_matches);
}
}
}

View File

@@ -0,0 +1,65 @@
package com.example.vdcscore.ui.gallery;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.vdcscore.R;
import java.util.List;
public class MatchesAdapter extends RecyclerView.Adapter<MatchesAdapter.ViewHolder> {
private List<Match> matches;
public MatchesAdapter(List<Match> matches) {
this.matches = matches;
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_match, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Match match = matches.get(position);
holder.textHomeTeam.setText(match.getHomeTeam());
holder.textAwayTeam.setText(match.getAwayTeam());
if ("Finished".equals(match.getStatus())) {
holder.textScore.setText(match.getHomeScore() + " - " + match.getAwayScore());
holder.textTime.setText("Final");
} else {
holder.textScore.setText("Vs");
holder.textTime.setText(match.getTime());
}
}
@Override
public int getItemCount() {
return matches == null ? 0 : matches.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public final TextView textHomeTeam;
public final TextView textAwayTeam;
public final TextView textScore;
public final TextView textTime;
public ViewHolder(View view) {
super(view);
textHomeTeam = view.findViewById(R.id.text_home_team);
textAwayTeam = view.findViewById(R.id.text_away_team);
textScore = view.findViewById(R.id.text_score);
textTime = view.findViewById(R.id.text_time);
}
}
}

View File

@@ -4,31 +4,90 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.example.vdcscore.databinding.FragmentHomeBinding;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class HomeFragment extends Fragment {
private FragmentHomeBinding binding;
private StandingsAdapter adapter;
private DatabaseReference mDatabase;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
HomeViewModel homeViewModel =
new ViewModelProvider(this).get(HomeViewModel.class);
ViewGroup container, Bundle savedInstanceState) {
binding = FragmentHomeBinding.inflate(inflater, container, false);
View root = binding.getRoot();
final TextView textView = binding.textHome;
homeViewModel.getText().observe(getViewLifecycleOwner(), textView::setText);
// Initialize RecyclerView
adapter = new StandingsAdapter();
binding.recyclerStandings.setLayoutManager(new LinearLayoutManager(getContext()));
binding.recyclerStandings.setAdapter(adapter);
// Initialize Firebase
mDatabase = FirebaseDatabase.getInstance().getReference("standings");
// Fetch Data
fetchStandings();
return root;
}
private void fetchStandings() {
mDatabase.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot snapshot) {
List<Team> teams = new ArrayList<>();
for (DataSnapshot postSnapshot : snapshot.getChildren()) {
Team team = postSnapshot.getValue(Team.class);
if (team != null) {
// If ID is missing, set it from the key
if (team.getId() == null) {
team.setId(postSnapshot.getKey());
}
teams.add(team);
}
}
// Sort by Points (Descending), then Goal Difference, then Goals For
Collections.sort(teams, new Comparator<Team>() {
@Override
public int compare(Team t1, Team t2) {
if (t1.getPoints() != t2.getPoints()) {
return t2.getPoints() - t1.getPoints(); // Descending points
}
return t2.getGoalDifference() - t1.getGoalDifference(); // Descending GD
}
});
adapter.setTeams(teams);
}
@Override
public void onCancelled(@NonNull DatabaseError error) {
if (getContext() != null) {
Toast.makeText(getContext(), "Erro ao carregar classificação: " + error.getMessage(),
Toast.LENGTH_SHORT).show();
}
}
});
}
@Override
public void onDestroyView() {
super.onDestroyView();

View File

@@ -0,0 +1,66 @@
package com.example.vdcscore.ui.home;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.vdcscore.R;
import java.util.ArrayList;
import java.util.List;
public class StandingsAdapter extends RecyclerView.Adapter<StandingsAdapter.ViewHolder> {
private List<Team> mTeams;
public StandingsAdapter() {
this.mTeams = new ArrayList<>();
}
public void setTeams(List<Team> teams) {
this.mTeams = teams;
notifyDataSetChanged();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_standing, parent, false);
return new ViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
Team team = mTeams.get(position);
holder.textPosition.setText(String.valueOf(position + 1));
holder.textTeamName.setText(team.getName());
holder.textPlayed.setText(String.valueOf(team.getPlayed()));
holder.textPoints.setText(String.valueOf(team.getPoints()));
}
@Override
public int getItemCount() {
return mTeams.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public final TextView textPosition;
public final TextView textTeamName;
public final TextView textPlayed;
public final TextView textPoints;
public ViewHolder(View view) {
super(view);
textPosition = view.findViewById(R.id.text_position);
textTeamName = view.findViewById(R.id.text_team_name);
textPlayed = view.findViewById(R.id.text_played);
textPoints = view.findViewById(R.id.text_points);
}
}
}

View File

@@ -0,0 +1,106 @@
package com.example.vdcscore.ui.home;
public class Team {
private String id;
private String name;
private int points;
private int played;
private int won;
private int drawn;
private int lost;
private int goalsFor;
private int goalsAgainst;
private int goalDifference;
public Team() {
// Required empty constructor for Firebase
}
public Team(String id, String name, int points, int played) {
this.id = id;
this.name = name;
this.points = points;
this.played = played;
}
// Getters and Setters
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPoints() {
return points;
}
public void setPoints(int points) {
this.points = points;
}
public int getPlayed() {
return played;
}
public void setPlayed(int played) {
this.played = played;
}
public int getWon() {
return won;
}
public void setWon(int won) {
this.won = won;
}
public int getDrawn() {
return drawn;
}
public void setDrawn(int drawn) {
this.drawn = drawn;
}
public int getLost() {
return lost;
}
public void setLost(int lost) {
this.lost = lost;
}
public int getGoalsFor() {
return goalsFor;
}
public void setGoalsFor(int goalsFor) {
this.goalsFor = goalsFor;
}
public int getGoalsAgainst() {
return goalsAgainst;
}
public void setGoalsAgainst(int goalsAgainst) {
this.goalsAgainst = goalsAgainst;
}
public int getGoalDifference() {
return goalDifference;
}
public void setGoalDifference(int goalDifference) {
this.goalDifference = goalDifference;
}
}

View File

@@ -0,0 +1,68 @@
package com.example.vdcscore.ui.livegames;
public class Game {
private String id;
private String homeTeam;
private String awayTeam;
private int homeScore;
private int awayScore;
private String time;
private int homePossession;
private int awayPossession;
private int homeShots;
private int awayShots;
public Game(String id, String homeTeam, String awayTeam, int homeScore, int awayScore, String time) {
this.id = id;
this.homeTeam = homeTeam;
this.awayTeam = awayTeam;
this.homeScore = homeScore;
this.awayScore = awayScore;
this.time = time;
// Default mocked stats
this.homePossession = 50;
this.awayPossession = 50;
this.homeShots = 5;
this.awayShots = 3;
}
public String getId() {
return id;
}
public String getHomeTeam() {
return homeTeam;
}
public String getAwayTeam() {
return awayTeam;
}
public int getHomeScore() {
return homeScore;
}
public int getAwayScore() {
return awayScore;
}
public String getTime() {
return time;
}
public int getHomePossession() {
return homePossession;
}
public int getAwayPossession() {
return awayPossession;
}
public int getHomeShots() {
return homeShots;
}
public int getAwayShots() {
return awayShots;
}
}

View File

@@ -0,0 +1,71 @@
package com.example.vdcscore.ui.livegames;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.example.vdcscore.R;
import java.util.List;
public class GameAdapter extends RecyclerView.Adapter<GameAdapter.GameViewHolder> {
private final List<Game> mGames;
private final OnGameClickListener mListener;
public interface OnGameClickListener {
void onGameClick(Game game);
}
public GameAdapter(List<Game> games, OnGameClickListener listener) {
mGames = games;
mListener = listener;
}
@NonNull
@Override
public GameViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_live_game, parent, false);
return new GameViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull GameViewHolder holder, int position) {
Game game = mGames.get(position);
holder.bind(game, mListener);
}
@Override
public int getItemCount() {
return mGames.size();
}
static class GameViewHolder extends RecyclerView.ViewHolder {
private final TextView time;
private final TextView homeTeam;
private final TextView awayTeam;
private final TextView score;
public GameViewHolder(@NonNull View itemView) {
super(itemView);
time = itemView.findViewById(R.id.text_game_time);
homeTeam = itemView.findViewById(R.id.text_home_team);
awayTeam = itemView.findViewById(R.id.text_away_team);
score = itemView.findViewById(R.id.text_score);
}
public void bind(final Game game, final OnGameClickListener listener) {
time.setText(game.getTime());
homeTeam.setText(game.getHomeTeam());
awayTeam.setText(game.getAwayTeam());
score.setText(game.getHomeScore() + " - " + game.getAwayScore());
itemView.setOnClickListener(v -> listener.onGameClick(game));
}
}
}

View File

@@ -0,0 +1,40 @@
package com.example.vdcscore.ui.livegames;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import java.util.ArrayList;
import java.util.List;
public class GameViewModel extends ViewModel {
private final MutableLiveData<List<Game>> mGames;
private final MutableLiveData<Game> mSelectedGame;
public GameViewModel() {
mGames = new MutableLiveData<>();
mSelectedGame = new MutableLiveData<>();
loadMockGames();
}
public LiveData<List<Game>> getGames() {
return mGames;
}
public LiveData<Game> getSelectedGame() {
return mSelectedGame;
}
public void selectGame(Game game) {
mSelectedGame.setValue(game);
}
private void loadMockGames() {
List<Game> games = new ArrayList<>();
games.add(new Game("1", "VDC", "Benfica", 2, 1, "45'"));
games.add(new Game("2", "Sporting", "Porto", 0, 0, "12'"));
games.add(new Game("3", "Braga", "V. Guimarães", 1, 3, "88'"));
mGames.setValue(games);
}
}

View File

@@ -0,0 +1,53 @@
package com.example.vdcscore.ui.livegames;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.ProgressBar;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import com.example.vdcscore.R;
import com.example.vdcscore.databinding.FragmentLiveGameDetailBinding;
public class LiveGameDetailFragment extends Fragment {
private FragmentLiveGameDetailBinding binding;
private GameViewModel gameViewModel;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
gameViewModel = new ViewModelProvider(requireActivity()).get(GameViewModel.class);
binding = FragmentLiveGameDetailBinding.inflate(inflater, container, false);
View root = binding.getRoot();
gameViewModel.getSelectedGame().observe(getViewLifecycleOwner(), game -> {
if (game != null) {
binding.detailGameTime.setText(game.getTime());
binding.detailHomeTeam.setText(game.getHomeTeam());
binding.detailAwayTeam.setText(game.getAwayTeam());
binding.detailScore.setText(game.getHomeScore() + " - " + game.getAwayScore());
binding.progressPossession.setProgress(game.getHomePossession());
binding.textPossessionHome.setText(game.getHomePossession() + "%");
binding.textPossessionAway.setText(game.getAwayPossession() + "%");
binding.textShotsHome.setText(String.valueOf(game.getHomeShots()));
binding.textShotsAway.setText(String.valueOf(game.getAwayShots()));
}
});
return root;
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}

View File

@@ -0,0 +1,49 @@
package com.example.vdcscore.ui.livegames;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.navigation.Navigation;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.example.vdcscore.R;
import com.example.vdcscore.databinding.FragmentLiveGamesBinding;
public class LiveGamesFragment extends Fragment {
private FragmentLiveGamesBinding binding;
private GameViewModel gameViewModel;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
gameViewModel = new ViewModelProvider(requireActivity()).get(GameViewModel.class);
binding = FragmentLiveGamesBinding.inflate(inflater, container, false);
View root = binding.getRoot();
RecyclerView recyclerView = binding.recyclerLiveGames;
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
gameViewModel.getGames().observe(getViewLifecycleOwner(), games -> {
GameAdapter adapter = new GameAdapter(games, game -> {
gameViewModel.selectGame(game);
Navigation.findNavController(root).navigate(R.id.action_nav_live_games_to_nav_live_game_detail);
});
recyclerView.setAdapter(adapter);
});
return root;
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF" />
<corners
android:topLeftRadius="30dp"
android:topRightRadius="30dp" />
</shape>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="#F5F5F5" />
<corners android:radius="12dp" />
<stroke
android:width="0dp"
android:color="#E0E0E0" />
</shape>

View File

@@ -2,7 +2,7 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="90"
android:angle="135"
android:startColor="#667eea"
android:endColor="#764ba2"
android:type="linear" />

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#FFFFFF" />
</shape>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#616161" />
<size
android:width="36dp"
android:height="36dp" />
</shape>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/background">
<shape>
<corners android:radius="6dp" />
<solid android:color="#E0E0E0" />
</shape>
</item>
<item android:id="@android:id/progress">
<clip>
<shape>
<corners android:radius="6dp" />
<solid android:color="@color/secondary_color" />
</shape>
</clip>
</item>
</layer-list>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@color/primary_color"/>
<corners android:radius="8dp"/>
</shape>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M19,4h-1V2h-2v2H8V2H6v2H5c-1.11,0 -1.99,0.9 -1.99,2L3,20c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V6c0,-1.1 -0.9,-2 -2,-2zM19,20H5V10h14v10zM19,8H5V6h14v2z"/>
</vector>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#90A4AE">
<path
android:fillColor="@android:color/white"
android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,8l-8,5 -8,-5L4,6l8,5 8,-5v2z"/>
</vector>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="412dp"
android:height="300dp"
android:viewportWidth="412"
android:viewportHeight="300">
<path
android:fillColor="#121212"
android:pathData="M0,0 L412,0 L412,220 C412,220 300,300 0,220 L0,0 Z" />
</vector>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="412dp"
android:height="200dp"
android:viewportWidth="412"
android:viewportHeight="200">
<path
android:fillColor="#121212"
android:pathData="M0,0 L412,0 L412,150 C300,200 100,200 0,150 L0,0 Z" />
</vector>

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

View File

@@ -1,30 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="108dp"
android:height="108dp"
android:viewportWidth="108"
android:viewportHeight="108">
<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
<aapt:attr name="android:fillColor">
<gradient
android:endX="85.84757"
android:endY="92.4963"
android:startX="42.9492"
android:startY="49.59793"
android:type="linear">
<item
android:color="#44000000"
android:offset="0.0" />
<item
android:color="#00000000"
android:offset="1.0" />
</gradient>
</aapt:attr>
</path>
<path
android:fillColor="#FFFFFF"
android:fillType="nonZero"
android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
android:strokeWidth="1"
android:strokeColor="#00000000" />
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM12,11.5c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5z"/>
</vector>

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#90A4AE">
<path
android:fillColor="@android:color/white"
android:pathData="M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM15.1,8L8.9,8L8.9,6c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>

View File

@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM18.92,8h-2.95c-0.32,-0.96 -0.78,-1.85 -1.35,-2.68 1.69,0.25 3.19,1.21 4.3,2.68zM14.53,7.69c-0.23,-0.69 -0.52,-1.36 -0.86,-1.99 -0.87,-0.3 -1.8,-0.48 -2.77,-0.48 -0.41,0 -0.81,0.04 -1.2,0.1 0.72,0.92 1.25,2.02 1.51,3.22h3.32zM8.33,5.32c-0.58,0.83 -1.04,1.72 -1.35,2.68H4.08c1.11,-1.47 2.61,-2.43 4.25,-2.68zM4.26,16h3.1c0.41,1.12 1.05,2.15 1.87,3.01 -1.97,-0.47 -3.67,-1.55 -4.97,-3.01zM4,12c0,-1.39 0.42,-2.68 1.13,-3.76 0.18,0.07 0.36,0.13 0.53,0.21 0.42,1.38 1.1,2.63 2,3.7 -0.85,1.02 -1.5,2.2 -1.92,3.5 0,0 -0.01,0 -0.01,0 -1.05,-1.03 -1.73,-2.45 -1.73,-4.06zM11.9,16.5c-1.3,0 -2.48,-0.62 -3.26,-1.59 0.73,-0.89 1.27,-1.93 1.57,-3.06h3.76l0,0c0.3,1.13 0.85,2.17 1.56,3.06 -0.78,0.97 -1.96,1.59 -3.26,1.59zM14.77,19.01c0.82,-0.86 1.46,-1.89 1.88,-3.01h3.1c-1.3,1.46 -3.01,2.54 -4.98,3.01zM17.16,11.94c0.42,-1.29 1.07,-2.48 1.92,-3.5 1.04,1.06 1.72,2.49 1.72,4.06 0,0.15 -0.01,0.29 -0.02,0.44 -1.13,-1.47 -2.62,-2.55 -4.26,-2.81 -0.19,0.64 -0.46,1.25 -0.78,1.82 0.5,0.38 0.98,0.81 1.42,1.29v-1.3z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/live_indicator" />
</shape>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@color/primary_light" />
<corners android:radius="8dp" />
</shape>

View File

@@ -1,10 +1,301 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_light"
tools:context=".ui.definicoes.ContaActivity">
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:elevation="0dp">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="@color/primary_color"
app:title="Definições de Conta"
app:titleTextColor="@color/white"
app:navigationIcon="@drawable/ic_arrow_back"
app:navigationIconTint="@color/white" />
</com.google.android.material.appbar.AppBarLayout>
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp">
<!-- Profile Photo Section -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/cardProfilePhoto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
app:cardCornerRadius="16dp"
app:cardElevation="2dp"
app:cardBackgroundColor="@color/surface_card"
app:strokeWidth="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Foto de Perfil"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@color/primary_color"
android:layout_marginBottom="24dp" />
<!-- Profile Image -->
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.google.android.material.card.MaterialCardView
android:id="@+id/cardImageContainer"
android:layout_width="120dp"
android:layout_height="120dp"
app:cardCornerRadius="60dp"
app:cardElevation="6dp"
app:cardBackgroundColor="#FFFFFF"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackgroundBorderless">
<ImageView
android:id="@+id/imageProfile"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:contentDescription="Foto de perfil"
android:src="@android:drawable/ic_menu_camera"
android:background="#E0E0E0" />
</com.google.android.material.card.MaterialCardView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabEditPhoto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:fabSize="mini"
app:backgroundTint="@color/secondary_color"
app:tint="@color/white"
android:src="@android:drawable/ic_menu_edit"
app:layout_constraintBottom_toBottomOf="@+id/cardImageContainer"
app:layout_constraintEnd_toEndOf="@+id/cardImageContainer"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:id="@+id/btnChangePhoto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Toque para alterar"
android:textColor="@color/text_secondary"
android:textSize="14sp"
android:textStyle="bold"
android:clickable="true"
android:focusable="true"
android:padding="8dp"
android:background="?attr/selectableItemBackgroundBorderless" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Name Section -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/cardName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
app:cardCornerRadius="16dp"
app:cardElevation="2dp"
app:cardBackgroundColor="@color/surface_card"
app:strokeWidth="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Nome de Utilizador"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@color/primary_color"
android:layout_marginBottom="16dp" />
<!-- Name Input -->
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Nome completo"
app:boxCornerRadiusTopStart="12dp"
app:boxCornerRadiusTopEnd="12dp"
app:boxCornerRadiusBottomStart="12dp"
app:boxCornerRadiusBottomEnd="12dp"
app:boxStrokeWidth="1dp"
app:boxStrokeColor="@color/divider"
app:startIconDrawable="@android:drawable/ic_menu_myplaces"
app:startIconTint="@color/text_secondary"
app:boxBackgroundMode="outline"
style="@style/Widget.Material3.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPersonName"
android:textColor="@color/text_primary"
android:textColorHint="@color/text_secondary"
android:textSize="16sp"
android:padding="16dp"
android:background="@android:color/transparent" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/btnSaveAll"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:backgroundTint="@color/primary_color"
android:text="Guardar Alterações"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Security Section -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/cardSecurity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
app:cardCornerRadius="16dp"
app:cardElevation="2dp"
app:cardBackgroundColor="@color/surface_card"
app:strokeWidth="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Segurança"
android:textSize="18sp"
android:textStyle="bold"
android:textColor="@color/primary_color"
android:layout_marginBottom="16dp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Email"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="@color/text_secondary"
android:layout_marginBottom="8dp" />
<TextView
android:id="@+id/textEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="email@exemplo.com"
android:textSize="16sp"
android:textColor="@color/text_primary"
android:padding="12dp"
android:background="@drawable/shape_score_bg"
android:backgroundTint="@color/background_light"
android:layout_marginBottom="12dp" />
<Button
android:id="@+id/btnChangeEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="@color/text_secondary"
android:text="Alterar Email"
android:textColor="@color/white" />
<Button
android:id="@+id/btnChangePassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:backgroundTint="@color/text_secondary"
android:text="Alterar Password"
android:textColor="@color/white" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
<!-- Logout Section -->
<com.google.android.material.card.MaterialCardView
android:id="@+id/cardLogout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
app:cardCornerRadius="16dp"
app:cardElevation="2dp"
app:cardBackgroundColor="@color/surface_card"
app:strokeWidth="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="24dp">
<Button
android:id="@+id/btnLogout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="@color/live_time"
android:text="Terminar Sessão"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -3,211 +3,189 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_gradient_login"
android:id="@+id/main">
android:background="#FFFFFF">
<!-- Título Criar Conta -->
<!-- Header Background -->
<ImageView
android:id="@+id/headerBg"
android:layout_width="match_parent"
android:layout_height="250dp"
android:scaleType="fitXY"
android:src="@drawable/ic_header_signup_bg"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<!-- Header Title (as per design image, showing "Sign Up" in header) or Body?
The image shows "Sign Up" text in the header area. -->
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="60dp"
android:text="Criar Conta"
android:textSize="42sp"
android:text="Sign Up"
android:textColor="#FFFFFF"
android:textSize="32sp"
android:textStyle="bold"
android:textColor="#FFFFFF"
android:letterSpacing="0.1"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="60dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintEnd_toEndOf="parent" />
<!-- Subtítulo VdcScore -->
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="VdcScore"
android:textSize="18sp"
android:textColor="#FFFFFF"
android:alpha="0.9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView" />
<!-- Back Button (Optional, not in Java but good for UX) -->
<!-- Card -->
<androidx.cardview.widget.CardView
android:id="@+id/cardRegister"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="24dp"
android:elevation="16dp"
android:padding="0dp"
app:cardCornerRadius="24dp"
app:cardUseCompatPadding="true"
app:cardBackgroundColor="#FFFFFF"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView4"
android:layout_marginTop="48dp">
<!-- Sign Up Form Container -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:fillViewport="true"
android:layout_marginTop="160dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="32dp">
android:paddingHorizontal="32dp"
android:paddingTop="20dp"
android:paddingBottom="20dp"
android:background="@drawable/bg_bottom_sheet_curve"> <!-- Implicit white background from activity, but layout structure follows scrolling -->
<!-- Título do Card -->
<!-- User Name Label -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Registar"
android:textSize="28sp"
android:text="Nome de Utilizador"
android:textColor="#212121"
android:textStyle="bold"
android:textColor="#263238"
android:layout_marginBottom="8dp" />
android:layout_marginBottom="8dp"
android:layout_marginStart="4dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Cria a tua conta para começar"
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editUserName"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/bg_input_field"
android:paddingHorizontal="16dp"
android:inputType="textPersonName"
android:hint="Tony"
android:textColor="#424242"
android:textColorHint="#BDBDBD"
android:textSize="14sp"
android:textColor="#90A4AE"
android:layout_marginBottom="24dp" />
<!-- Email -->
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
<!-- Email Label -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:hint="Email"
app:boxStrokeColor="#667eea"
app:hintTextColor="#667eea"
app:startIconDrawable="@drawable/ic_email"
app:startIconTint="#667eea"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
app:boxCornerRadiusTopStart="12dp"
app:boxCornerRadiusTopEnd="12dp"
app:boxCornerRadiusBottomStart="12dp"
app:boxCornerRadiusBottomEnd="12dp">
android:text="Email"
android:textColor="#212121"
android:textStyle="bold"
android:layout_marginBottom="8dp"
android:layout_marginStart="4dp"/>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"
android:textColor="#263238"
android:textSize="16sp" />
</com.google.android.material.textfield.TextInputLayout>
<!-- Password -->
<com.google.android.material.textfield.TextInputLayout
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editEmail"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/bg_input_field"
android:paddingHorizontal="16dp"
android:inputType="textEmailAddress"
android:hint="email@exemplo.com"
android:textColor="#424242"
android:textColorHint="#BDBDBD"
android:textSize="14sp"
android:layout_marginBottom="24dp" />
<!-- Password Label -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:hint="Password"
app:boxStrokeColor="#667eea"
app:hintTextColor="#667eea"
app:startIconDrawable="@drawable/ic_lock"
app:startIconTint="#667eea"
app:endIconMode="password_toggle"
app:endIconTint="#667eea"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
app:boxCornerRadiusTopStart="12dp"
app:boxCornerRadiusTopEnd="12dp"
app:boxCornerRadiusBottomStart="12dp"
app:boxCornerRadiusBottomEnd="12dp">
android:text="Password"
android:textColor="#212121"
android:textStyle="bold"
android:layout_marginBottom="8dp"
android:layout_marginStart="4dp"/>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editPassword2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:textColor="#263238"
android:textSize="16sp" />
</com.google.android.material.textfield.TextInputLayout>
<!-- Confirmar Password -->
<com.google.android.material.textfield.TextInputLayout
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editPassword2"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/bg_input_field"
android:paddingHorizontal="16dp"
android:inputType="textPassword"
android:hint="********"
android:textColor="#424242"
android:textColorHint="#BDBDBD"
android:textSize="14sp"
android:layout_marginBottom="24dp" />
<!-- Confirm Password Label -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:hint="Confirmar Password"
app:boxStrokeColor="#667eea"
app:hintTextColor="#667eea"
app:startIconDrawable="@drawable/ic_lock"
app:startIconTint="#667eea"
app:endIconMode="password_toggle"
app:endIconTint="#667eea"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
app:boxCornerRadiusTopStart="12dp"
app:boxCornerRadiusTopEnd="12dp"
app:boxCornerRadiusBottomStart="12dp"
app:boxCornerRadiusBottomEnd="12dp">
android:text="Confirmar Password"
android:textColor="#212121"
android:textStyle="bold"
android:layout_marginBottom="8dp"
android:layout_marginStart="4dp"/>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editConfirmPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:textColor="#263238"
android:textSize="16sp" />
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editConfirmPassword"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/bg_input_field"
android:paddingHorizontal="16dp"
android:inputType="textPassword"
android:hint="********"
android:textColor="#424242"
android:textColorHint="#BDBDBD"
android:textSize="14sp"
android:layout_marginBottom="32dp" />
</com.google.android.material.textfield.TextInputLayout>
<!-- Botão -->
<!-- Sign Up Button -->
<Button
android:id="@+id/btnCreateAccount"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginTop="8dp"
android:background="@drawable/button_modern"
android:text="Criar Conta"
android:textColor="#FFFFFF"
android:layout_height="55dp"
android:text="Sign Up"
android:textAllCaps="false"
android:textSize="16sp"
android:textStyle="bold"
android:elevation="4dp"
android:stateListAnimator="@null" />
android:textColor="#FFFFFF"
android:backgroundTint="#000000"
app:cornerRadius="12dp"
android:layout_marginBottom="24dp" />
<!-- Login Link -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Já tem uma conta? "
android:textColor="#757575" />
<TextView
android:id="@+id/txtGoLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sign In"
android:textColor="#000000"
android:textStyle="bold"
android:clickable="true"
android:focusable="true"/>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Voltar ao Login -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cardRegister">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Já tens conta? "
android:textColor="#FFFFFF"
android:textSize="14sp"
android:alpha="0.9" />
<TextView
android:id="@+id/txtGoLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Entrar"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:textSize="14sp"
android:clickable="true"
android:focusable="true"
android:padding="4dp" />
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -5,195 +5,177 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_gradient_login">
android:background="#FFFFFF">
<!-- Título VdcScore -->
<TextView
android:id="@+id/textView3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="80dp"
android:text="VdcScore"
android:textSize="42sp"
android:textStyle="bold"
android:textColor="#FFFFFF"
android:letterSpacing="0.1"
<!-- Header Background -->
<ImageView
android:id="@+id/headerBg"
android:layout_width="match_parent"
android:layout_height="300dp"
android:scaleType="fitXY"
android:src="@drawable/ic_header_login_bg"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
<!-- Logo -->
<ImageView
android:id="@+id/logoImage"
android:layout_width="77dp"
android:layout_height="80dp"
android:layout_marginTop="60dp"
android:elevation="4dp"
android:src="@mipmap/ic_launcher"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- Subtítulo -->
<TextView
android:id="@+id/textViewSubtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="Bem-vindo de volta!"
android:textSize="18sp"
android:textColor="#FFFFFF"
android:alpha="0.9"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView3" />
<!-- Login Form Container -->
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:fillViewport="true"
android:layout_marginTop="-40dp"
app:layout_constraintTop_toBottomOf="@+id/headerBg"
app:layout_constraintBottom_toBottomOf="parent">
<!-- Card -->
<androidx.cardview.widget.CardView
android:id="@+id/cardLogin"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="24dp"
android:elevation="16dp"
android:padding="0dp"
app:cardCornerRadius="24dp"
app:cardUseCompatPadding="true"
app:cardBackgroundColor="#FFFFFF"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textViewSubtitle"
android:layout_marginTop="48dp">
<LinearLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="32dp">
android:paddingHorizontal="32dp"
android:paddingTop="20dp"
android:paddingBottom="20dp">
<!-- Título do Card -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Entrar"
android:textSize="28sp"
android:text="Login"
android:textSize="32sp"
android:textStyle="bold"
android:textColor="#263238"
android:layout_marginBottom="8dp" />
android:textColor="#212121"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="40dp" />
<!-- Email Label -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Insira as suas credenciais"
android:textSize="14sp"
android:textColor="#90A4AE"
android:layout_marginBottom="24dp" />
<!-- Email -->
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:hint="Email"
app:boxStrokeColor="#667eea"
app:hintTextColor="#667eea"
app:startIconDrawable="@drawable/ic_email"
app:startIconTint="#667eea"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
app:boxCornerRadiusTopStart="12dp"
app:boxCornerRadiusTopEnd="12dp"
app:boxCornerRadiusBottomStart="12dp"
app:boxCornerRadiusBottomEnd="12dp">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"
android:textColor="#263238"
android:textSize="16sp" />
</com.google.android.material.textfield.TextInputLayout>
<!-- Password -->
<com.google.android.material.textfield.TextInputLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Email"
android:textColor="#212121"
android:textStyle="bold"
android:layout_marginBottom="8dp"
android:hint="Password"
app:boxStrokeColor="#667eea"
app:hintTextColor="#667eea"
app:startIconDrawable="@drawable/ic_lock"
app:startIconTint="#667eea"
app:endIconMode="password_toggle"
app:endIconTint="#667eea"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
app:boxCornerRadiusTopStart="12dp"
app:boxCornerRadiusTopEnd="12dp"
app:boxCornerRadiusBottomStart="12dp"
app:boxCornerRadiusBottomEnd="12dp">
android:layout_marginStart="4dp"/>
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editPassword2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:textColor="#263238"
android:textSize="16sp" />
</com.google.android.material.textfield.TextInputLayout>
<!-- Esqueceu a senha -->
<TextView
android:id="@+id/txtForgotPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:text="Esqueceu a senha?"
android:textColor="#667eea"
<!-- Email Input -->
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editEmail"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/bg_input_field"
android:paddingHorizontal="16dp"
android:inputType="textEmailAddress"
android:hint="email@exemplo.com"
android:textColor="#424242"
android:textColorHint="#BDBDBD"
android:textSize="14sp"
android:textStyle="bold"
android:padding="8dp"
android:clickable="true"
android:focusable="true"
android:layout_marginBottom="24dp" />
<!-- Botão -->
<!-- Password Label -->
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Password"
android:textColor="#212121"
android:textStyle="bold"
android:layout_marginBottom="8dp"
android:layout_marginStart="4dp"/>
<!-- Password Input -->
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editPassword2"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/bg_input_field"
android:paddingHorizontal="16dp"
android:inputType="textPassword"
android:hint="********"
android:textColor="#424242"
android:textColorHint="#BDBDBD"
android:textSize="14sp"
android:layout_marginBottom="16dp" />
<!-- Remember Me & Forgot Password -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginBottom="32dp">
<CheckBox
android:id="@+id/checkRememberMe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Lembrar"
android:textColor="#757575"/>
<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1" />
<TextView
android:id="@+id/txtForgotPassword"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Esqueceu a senha?"
android:textColor="#757575"
android:textStyle="bold"
android:textSize="12sp"
android:clickable="true"
android:focusable="true"/>
</LinearLayout>
<!-- Login Button -->
<Button
android:id="@+id/btnLogin"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginTop="8dp"
android:background="@drawable/button_modern"
android:text="Entrar"
android:textColor="#FFFFFF"
android:layout_height="55dp"
android:text="Login"
android:textAllCaps="false"
android:textSize="16sp"
android:textStyle="bold"
android:elevation="4dp"
android:stateListAnimator="@null" />
android:textColor="#FFFFFF"
android:backgroundTint="#000000"
app:cornerRadius="12dp"
android:layout_marginBottom="24dp" />
<!-- Sign Up Link -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Não tem uma conta? "
android:textColor="#757575" />
<TextView
android:id="@+id/txtRegister"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Criar Conta"
android:textColor="#000000"
android:textStyle="bold"
android:clickable="true"
android:focusable="true"/>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
<!-- Criar conta -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cardLogin">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Não tens conta? "
android:textColor="#FFFFFF"
android:textSize="14sp"
android:alpha="0.9" />
<TextView
android:id="@+id/txtRegister"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Criar conta"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:textSize="14sp"
android:clickable="true"
android:focusable="true"
android:padding="4dp" />
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -20,6 +20,9 @@
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
android:background="@color/white"
app:itemTextColor="@color/black"
app:itemIconTint="@color/black"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>

View File

@@ -5,63 +5,74 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_gradient_login">
android:background="@drawable/bg_gradient">
<!-- Título -->
<!-- Back Button -->
<ImageButton
android:id="@+id/btnBack"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:background="?attr/selectableItemBackgroundBorderless"
android:src="@drawable/ic_arrow_back"
android:tint="#FFFFFF"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- Logo/Title -->
<TextView
android:id="@+id/textViewTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="100dp"
android:text="Recuperar Senha"
android:textSize="42sp"
android:layout_marginTop="60dp"
android:text="Recuperar Palavra-passe"
android:textSize="28sp"
android:textStyle="bold"
android:textColor="#FFFFFF"
android:letterSpacing="0.1"
android:gravity="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<!-- Subtítulo -->
<!-- Subtitle -->
<TextView
android:id="@+id/textViewSubtitle"
android:id="@+id/textSubtitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:layout_marginTop="16dp"
android:text="Insira o seu email e enviaremos um link para redefinir a sua senha"
android:textSize="16sp"
android:text="Introduza o seu email e enviaremos instruções para recuperar a sua palavra-passe"
android:textSize="14sp"
android:textColor="#FFFFFF"
android:alpha="0.9"
android:gravity="center"
android:lineSpacingExtra="4dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textViewTitle" />
<!-- Card -->
<androidx.cardview.widget.CardView
android:id="@+id/cardRecover"
android:id="@+id/cardRecuperar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="24dp"
android:elevation="16dp"
android:padding="0dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:layout_marginTop="48dp"
android:elevation="8dp"
android:padding="28dp"
app:cardCornerRadius="24dp"
app:cardUseCompatPadding="true"
app:cardBackgroundColor="#FFFFFF"
app:layout_constraintBottom_toBottomOf="parent"
app:cardUseCompatPadding="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textViewSubtitle"
android:layout_marginTop="48dp">
app:layout_constraintTop_toBottomOf="@+id/textSubtitle">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="32dp">
android:orientation="vertical">
<!-- Email -->
<com.google.android.material.textfield.TextInputLayout
@@ -69,34 +80,34 @@
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:hint="Email"
app:boxStrokeColor="#667eea"
app:hintTextColor="#667eea"
app:startIconDrawable="@drawable/ic_email"
app:startIconTint="#667eea"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
app:boxCornerRadiusTopStart="12dp"
app:boxCornerRadiusTopEnd="12dp"
app:boxCornerRadiusBottomStart="12dp"
app:boxCornerRadiusBottomEnd="12dp">
app:boxCornerRadiusBottomEnd="12dp"
app:boxStrokeWidth="0dp"
app:startIconDrawable="@android:drawable/ic_dialog_email"
app:startIconTint="#667eea"
style="@style/Widget.Material3.TextInputLayout.OutlinedBox">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/editEmailRecover"
android:id="@+id/editEmailRecuperar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"
android:textColor="#263238"
android:textSize="16sp" />
android:textColorHint="#90A4AE"
android:padding="16dp" />
</com.google.android.material.textfield.TextInputLayout>
<!-- Botão -->
<Button
android:id="@+id/btnSendRecovery"
android:id="@+id/btnRecuperar"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginTop="8dp"
android:background="@drawable/button_modern"
android:text="Enviar Link de Recuperação"
android:text="Enviar Email"
android:textColor="#FFFFFF"
android:textSize="16sp"
android:textStyle="bold"
@@ -111,31 +122,33 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="24dp"
android:orientation="horizontal"
android:gravity="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/cardRecover">
app:layout_constraintTop_toBottomOf="@+id/cardRecuperar">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Lembras-te da senha? "
android:text="Lembras-te da palavra-passe? "
android:textColor="#FFFFFF"
android:textSize="14sp"
android:alpha="0.9" />
<TextView
android:id="@+id/txtBackToLogin"
android:id="@+id/txtVoltarLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Voltar ao Login"
android:text="Entrar"
android:textColor="#FFFFFF"
android:textStyle="bold"
android:textSize="14sp"
android:clickable="true"
android:focusable="true"
android:padding="4dp" />
android:padding="4dp"
android:background="?attr/selectableItemBackground" />
</LinearLayout>

View File

@@ -9,26 +9,21 @@
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/Theme.VdcScore.AppBarOverlay">
android:background="@color/white"
android:theme="@style/ThemeOverlay.AppCompat.Light"> <!-- Light theme for dark text -->
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:background="@color/white"
app:titleTextColor="@color/black"
app:popupTheme="@style/Theme.VdcScore.PopupOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="@layout/content_main" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginEnd="@dimen/fab_margin"
android:layout_marginBottom="16dp"
app:srcCompat="@android:drawable/ic_dialog_email" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -0,0 +1,232 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:background="@color/white"
tools:context=".ui.clubs.ClubDetailFragment">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="24dp">
<!-- Club Logo (Circular) -->
<androidx.cardview.widget.CardView
android:id="@+id/cardLogo"
android:layout_width="200dp"
android:layout_height="200dp"
app:cardCornerRadius="100dp"
app:cardElevation="8dp"
app:cardBackgroundColor="@color/white"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp">
<ImageView
android:id="@+id/image_detail_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:padding="0dp"
tools:src="@mipmap/ic_launcher_round"/>
</androidx.cardview.widget.CardView>
<!-- CLUBE Label -->
<TextView
android:id="@+id/label_club"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="CLUBE:"
android:textSize="14sp"
android:textColor="#616161"
android:layout_marginTop="32dp"
app:layout_constraintTop_toBottomOf="@id/cardLogo"
app:layout_constraintStart_toStartOf="parent"/>
<!-- Club Name -->
<TextView
android:id="@+id/text_detail_club_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
tools:text="Inter Freguesias Vila do Conde"
android:textSize="28sp"
android:textStyle="bold"
android:textColor="#0D47A1"
android:layout_marginTop="4dp"
app:layout_constraintTop_toBottomOf="@id/label_club"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<!-- President Section -->
<LinearLayout
android:id="@+id/layout_president"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginTop="24dp"
app:layout_constraintTop_toBottomOf="@id/text_detail_club_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_person"
app:tint="#455A64"
android:background="@drawable/circle_edit_background"
android:backgroundTint="#ECEFF1"
android:padding="8dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginStart="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PRESIDENTE:"
android:textSize="12sp"
android:textColor="#616161"/>
<TextView
android:id="@+id/text_detail_president"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="João Silva"
android:textSize="16sp"
android:textColor="#263238"
android:textStyle="bold"/>
</LinearLayout>
</LinearLayout>
<!-- Address Section -->
<LinearLayout
android:id="@+id/layout_address"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@id/layout_president"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_location"
app:tint="#455A64"
android:background="@drawable/circle_edit_background"
android:backgroundTint="#ECEFF1"
android:padding="8dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginStart="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="MORADA:"
android:textSize="12sp"
android:textColor="#616161"/>
<TextView
android:id="@+id/text_detail_address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="Rua Desportiva 123"
android:textSize="16sp"
android:textColor="#263238"
android:textStyle="bold"/>
</LinearLayout>
</LinearLayout>
<!-- Foundation Section -->
<LinearLayout
android:id="@+id/layout_foundation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@id/layout_address"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_calendar"
app:tint="#455A64"
android:background="@drawable/circle_edit_background"
android:backgroundTint="#ECEFF1"
android:padding="8dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginStart="16dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ANO DE FUNDAÇÃO:"
android:textSize="12sp"
android:textColor="#616161"/>
<TextView
android:id="@+id/text_detail_foundation"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="1995"
android:textSize="16sp"
android:textColor="#263238"
android:textStyle="bold"/>
</LinearLayout>
</LinearLayout>
<!-- Stadium Section (Hidden per screenshot but kept in model, or should I show it?)
The screenshot doesn't explicitly show Stadium but the code had it.
I will hide it for now to match screenshot strictly or add it if plenty space?
The user said "appears like this", implies following the screenshot.
But previously stadium was shown. I will add it as well for completeness if it fits,
or just omit if the screenshot is strict.
Screenshot: CLUBE, PRESIDENTE, MORADA, ANO DE FUNDACAO. No Stadium.
I will omit Stadium from UI to match unique request "like this".
-->
<!-- Players Button -->
<Button
android:id="@+id/btn_players"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="JOGADORES\n(Ver Lista)"
android:textColor="@color/white"
android:textSize="16sp"
android:textStyle="bold"
app:cornerRadius="12dp"
android:backgroundTint="#1976D2"
app:icon="@drawable/ic_soccer"
app:iconGravity="textStart"
app:iconSize="32dp"
app:iconTint="@color/white"
android:gravity="center"
android:layout_marginTop="40dp"
app:layout_constraintTop_toBottomOf="@id/layout_foundation"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="1.0"
android:layout_marginBottom="20dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.core.widget.NestedScrollView>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F5F5F5"
tools:context=".ui.clubs.ClubPlayersFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_players_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="@+id/text_no_players"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Sem jogadores inscritos"
android:textSize="18sp"
android:textColor="#757575"
android:visibility="gone"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<ProgressBar
android:id="@+id/progressBarPlayers"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_light">
<com.google.android.material.button.MaterialButtonToggleGroup
android:id="@+id/toggleGroupEscalao"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:checkedButton="@id/btnSeniores"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:singleSelection="true">
<com.google.android.material.button.MaterialButton
android:id="@+id/btnSeniores"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Seniores" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btnJuniores"
style="?attr/materialButtonOutlinedStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Juniores" />
</com.google.android.material.button.MaterialButtonToggleGroup>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_clubs"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/toggleGroupEscalao" />
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ECEFF1">
android:background="@color/background_light">
<LinearLayout
android:layout_width="match_parent"
@@ -16,7 +16,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Definições"
android:textColor="#263238"
android:textColor="@color/primary_color"
android:textSize="28sp"
android:textStyle="bold" />
@@ -25,7 +25,7 @@
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Personaliza a aplicação de acordo com o teu gosto."
android:textColor="#546E7A"
android:textColor="@color/text_secondary"
android:textSize="14sp" />
<com.google.android.material.card.MaterialCardView
@@ -33,30 +33,34 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:clickable="true"
android:focusable="true"
android:foreground="?attr/selectableItemBackground"
app:cardCornerRadius="16dp"
app:cardUseCompatPadding="true"
app:strokeColor="#CFD8DC"
app:strokeWidth="1dp">
app:cardElevation="0dp"
app:strokeColor="@color/divider"
app:strokeWidth="1dp"
app:cardBackgroundColor="@color/surface_card">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="18dp">
android:padding="20dp">
<ImageView
android:layout_width="40dp"
android:layout_height="40dp"
android:contentDescription="@string/menu_definicoes"
android:padding="4dp"
android:src="@android:drawable/ic_menu_manage" />
android:src="@android:drawable/ic_menu_manage"
app:tint="@color/black"/>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginStart="16dp"
android:layout_weight="1"
android:orientation="vertical">
@@ -64,7 +68,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Conta"
android:textColor="#263238"
android:textColor="@color/black"
android:textSize="18sp"
android:textStyle="bold" />
@@ -72,7 +76,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Atualiza os teus dados pessoais"
android:textColor="#607D8B"
android:textColor="@color/text_secondary"
android:textSize="14sp" />
</LinearLayout>
@@ -80,7 +84,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/menu_definicoes"
android:src="@android:drawable/ic_media_next" />
android:src="@android:drawable/ic_media_next"
app:tint="@color/text_secondary"/>
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
@@ -89,13 +94,16 @@
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:cardCornerRadius="16dp"
app:cardUseCompatPadding="true">
app:cardElevation="0dp"
app:strokeColor="@color/divider"
app:strokeWidth="1dp"
app:cardBackgroundColor="@color/surface_card">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="18dp">
android:padding="20dp">
<LinearLayout
android:layout_width="match_parent"
@@ -113,7 +121,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Notificações"
android:textColor="#263238"
android:textColor="@color/black"
android:textSize="16sp"
android:textStyle="bold" />
@@ -122,7 +130,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Ativadas"
android:textColor="#607D8B"
android:textColor="@color/text_secondary"
android:textSize="14sp" />
</LinearLayout>
@@ -136,8 +144,8 @@
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginVertical="12dp"
android:background="#ECEFF1" />
android:layout_marginVertical="16dp"
android:background="@color/divider" />
<LinearLayout
android:layout_width="match_parent"
@@ -155,7 +163,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Modo escuro"
android:textColor="#263238"
android:textColor="@color/black"
android:textSize="16sp"
android:textStyle="bold" />
@@ -164,7 +172,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Inativo"
android:textColor="#607D8B"
android:textColor="@color/text_secondary"
android:textSize="14sp" />
</LinearLayout>
@@ -181,19 +189,22 @@
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
app:cardCornerRadius="16dp"
app:cardUseCompatPadding="true">
app:cardElevation="0dp"
app:strokeColor="@color/divider"
app:strokeWidth="1dp"
app:cardBackgroundColor="@color/surface_card">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="18dp">
android:padding="20dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Ajuda e suporte"
android:textColor="#263238"
android:textColor="@color/black"
android:textSize="16sp"
android:textStyle="bold" />
@@ -202,20 +213,19 @@
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="Consulta a nossa base de conhecimento ou fala connosco."
android:textColor="#607D8B"
android:textColor="@color/text_secondary"
android:textSize="14sp" />
<Button
android:id="@+id/btnOpenSystemSettings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:backgroundTint="#1E88E5"
android:layout_marginTop="16dp"
android:backgroundTint="@color/black"
android:text="Abrir definições do sistema"
android:textAllCaps="false"
android:textColor="#FFFFFF" />
android:textColor="@color/white" />
</LinearLayout>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
</ScrollView>

View File

@@ -1,22 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
android:background="@color/background_light"
tools:context=".ui.gallery.GalleryFragment">
<TextView
android:id="@+id/text_gallery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
android:text="Jornadas"
android:textSize="24sp"
android:textStyle="bold"
android:textColor="@color/primary_color"
android:layout_marginBottom="16dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_matchdays"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:paddingBottom="16dp"/>
</LinearLayout>

View File

@@ -1,22 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
android:background="@color/background_light"
tools:context=".ui.home.HomeFragment">
<TextView
android:id="@+id/text_home"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
android:text="Classificação"
android:textSize="28sp"
android:textStyle="bold"
android:textColor="@color/primary_color"
android:layout_marginBottom="24dp" />
<!-- Table Header (Clean) -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingVertical="12dp"
android:paddingHorizontal="4dp"
android:background="#00000000">
<TextView
android:layout_width="40dp"
android:layout_height="wrap_content"
android:text="#"
android:textStyle="bold"
android:textColor="@color/black"
android:textSize="14sp"/>
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Clube"
android:textStyle="bold"
android:textColor="@color/black"
android:textSize="14sp"/>
<TextView
android:layout_width="40dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="J"
android:textStyle="bold"
android:textColor="@color/black"
android:textSize="14sp"
android:tooltipText="Jogos" />
<TextView
android:layout_width="40dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Pts"
android:textStyle="bold"
android:textColor="@color/black"
android:textSize="14sp"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/divider"
android:layout_marginBottom="8dp"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_standings"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:clipToPadding="false"
android:paddingTop="4dp" />
</LinearLayout>

View File

@@ -0,0 +1,201 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_light">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<!-- Header Card -->
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardBackgroundColor="@color/primary_color"
app:cardCornerRadius="24dp"
app:cardElevation="6dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="24dp">
<TextView
android:id="@+id/detail_game_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="65'"
android:textColor="@color/live_time"
android:textSize="18sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/detail_home_team"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="Home"
android:textColor="@color/white"
android:textSize="22sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/detail_score"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/detail_game_time" />
<TextView
android:id="@+id/detail_score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:text="1 - 1"
android:textColor="@color/white"
android:textSize="36sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/detail_home_team"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/detail_home_team" />
<TextView
android:id="@+id/detail_away_team"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Away"
android:textColor="@color/white"
android:textSize="22sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/detail_home_team"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/detail_score"
app:layout_constraintTop_toTopOf="@+id/detail_home_team" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
<!-- Stats Section -->
<TextView
android:id="@+id/text_stats_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:layout_marginBottom="16dp"
android:text="Estatísticas ao Vivo"
android:textColor="@color/text_primary"
android:textSize="20sp"
android:textStyle="bold" />
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:cardCornerRadius="16dp"
app:cardElevation="2dp"
app:cardBackgroundColor="@color/surface_card">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="20dp">
<!-- Possession -->
<TextView
android:id="@+id/label_possession"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Posse de Bola"
android:textColor="@color/text_secondary"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="8dp"
android:gravity="center_vertical">
<TextView
android:id="@+id/text_possession_home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="50%"
android:textStyle="bold"
android:textColor="@color/text_primary"
android:layout_marginEnd="12dp"/>
<ProgressBar
android:id="@+id/progress_possession"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="0dp"
android:layout_height="12dp"
android:layout_weight="1"
android:max="100"
android:progress="50"
android:progressDrawable="@drawable/custom_progress_bg"/>
<TextView
android:id="@+id/text_possession_away"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="50%"
android:textStyle="bold"
android:textColor="@color/text_primary"
android:layout_marginStart="12dp"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/divider"
android:layout_marginVertical="16dp"/>
<!-- Shots -->
<TextView
android:id="@+id/label_shots"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Remates"
android:textColor="@color/text_secondary"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="8dp"
android:gravity="center">
<TextView
android:id="@+id/text_shots_home"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="5"
android:textSize="24sp"
android:textStyle="bold"
android:textColor="@color/secondary_color"
android:layout_marginEnd="32dp"/>
<TextView
android:id="@+id/text_shots_away"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="3"
android:textSize="24sp"
android:textStyle="bold"
android:textColor="@color/secondary_color"
android:layout_marginStart="32dp"/>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
</ScrollView>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background_light">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_live_games"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="8dp"
android:clipToPadding="false"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/text_no_games"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Não há jogos ao vivo no momento"
android:textSize="16sp"
android:textColor="@color/text_secondary"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="6dp"
app:cardBackgroundColor="@color/surface_card"
app:cardCornerRadius="12dp"
app:cardElevation="2dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
<androidx.cardview.widget.CardView
android:id="@+id/card_logo"
android:layout_width="50dp"
android:layout_height="50dp"
app:cardCornerRadius="25dp"
app:cardElevation="0dp"
app:cardBackgroundColor="#F0F0F0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="@+id/image_club_logo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/ic_menu_gallery"
android:padding="8dp"/>
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/text_club_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="Club Name"
android:textColor="@color/text_primary"
android:textSize="17sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="@+id/text_club_stadium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/card_logo"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_chainStyle="packed"/>
<TextView
android:id="@+id/text_club_stadium"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="2dp"
android:text="Stadium Name"
android:textColor="@color/text_secondary"
android:textSize="14sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/text_club_name"
app:layout_constraintTop_toBottomOf="@+id/text_club_name" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>

View File

@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="8dp"
app:cardBackgroundColor="@color/surface_card"
app:cardCornerRadius="16dp"
app:cardElevation="2dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp">
<TextView
android:id="@+id/text_game_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="45'"
android:textColor="@color/live_time"
android:textSize="14sp"
android:textStyle="bold"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:id="@+id/live_indicator"
android:layout_width="8dp"
android:layout_height="8dp"
android:layout_marginEnd="6dp"
android:background="@drawable/shape_circle_live"
app:layout_constraintBottom_toBottomOf="@+id/text_game_time"
app:layout_constraintEnd_toStartOf="@+id/text_game_time"
app:layout_constraintTop_toTopOf="@+id/text_game_time" />
<TextView
android:id="@+id/text_home_team"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:gravity="center"
android:text="Home Team"
android:textColor="@color/text_primary"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintEnd_toStartOf="@+id/text_score"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/text_game_time" />
<TextView
android:id="@+id/text_score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:background="@drawable/shape_score_bg"
android:paddingHorizontal="16dp"
android:paddingVertical="6dp"
android:text="2 - 1"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/text_home_team"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/text_home_team" />
<TextView
android:id="@+id/text_away_team"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Away Team"
android:textColor="@color/text_primary"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="@+id/text_home_team"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/text_score"
app:layout_constraintTop_toTopOf="@+id/text_home_team" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical"
android:padding="8dp">
<!-- Home Team -->
<TextView
android:id="@+id/text_home_team"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="end"
android:text="Home"
android:textStyle="bold"
android:textColor="@color/text_primary" />
<!-- Score / Time -->
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="12dp"
android:gravity="center"
android:orientation="vertical"
android:minWidth="60dp">
<TextView
android:id="@+id/text_score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Vs"
android:textStyle="bold"
android:textColor="@color/secondary_color"
android:textSize="16sp" />
<TextView
android:id="@+id/text_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="15:00"
android:textSize="12sp"
android:textColor="@color/text_secondary" />
</LinearLayout>
<!-- Away Team -->
<TextView
android:id="@+id/text_away_team"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="start"
android:text="Away"
android:textStyle="bold"
android:textColor="@color/text_primary" />
</LinearLayout>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
app:cardCornerRadius="12dp"
app:cardElevation="4dp"
app:contentPadding="0dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<!-- Header -->
<TextView
android:id="@+id/text_matchday_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/primary_light"
android:textColor="@color/white"
android:padding="12dp"
android:text="Jornada 1"
android:textStyle="bold"
android:textSize="16sp" />
<!-- Matches List -->
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_matches"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:nestedScrollingEnabled="false"
tools:itemCount="3"
tools:listitem="@layout/item_match" xmlns:tools="http://schemas.android.com/tools"/>
</LinearLayout>
</androidx.cardview.widget.CardView>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="16dp"
android:gravity="center_vertical">
<ImageView
android:id="@+id/image_player_icon"
android:layout_width="40dp"
android:layout_height="40dp"
android:src="@drawable/ic_menu_camera"
android:contentDescription="Player Icon"
android:layout_marginEnd="16dp"/>
<TextView
android:id="@+id/text_player_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Player Name"
android:textSize="16sp"
android:textStyle="bold" />
</LinearLayout>

View File

@@ -0,0 +1,59 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingVertical="16dp"
android:paddingHorizontal="4dp"
android:gravity="center_vertical"
android:background="?attr/selectableItemBackground">
<TextView
android:id="@+id/text_position"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:text="1"
android:textStyle="bold"
android:textColor="@color/black"
android:textSize="16sp" />
<TextView
android:id="@+id/text_team_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="Team Name"
android:textColor="@color/black"
android:textSize="16sp"
android:textStyle="normal" />
<TextView
android:id="@+id/text_played"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="P"
android:textColor="@color/text_secondary"
android:textSize="14sp" />
<TextView
android:id="@+id/text_points"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="Pts"
android:textStyle="bold"
android:textColor="@color/black"
android:textSize="14sp" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#F5F5F5"/>
</LinearLayout>

View File

@@ -1,35 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/nav_header_height"
android:background="@drawable/side_nav_bar"
android:gravity="bottom"
android:layout_height="200dp"
android:background="@drawable/ic_header_login_bg"
android:gravity="top"
android:orientation="vertical"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
android:theme="@style/ThemeOverlay.AppCompat.Light">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/nav_header_desc"
android:paddingTop="@dimen/nav_header_vertical_spacing"
app:srcCompat="@mipmap/ic_launcher_round" />
<androidx.cardview.widget.CardView
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginTop="10dp"
app:cardCornerRadius="40dp"
app:cardBackgroundColor="@color/white"
app:cardElevation="4dp">
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/nav_header_desc"
android:scaleType="centerCrop"
app:srcCompat="@mipmap/ic_launcher_round" />
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/textViewName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="@dimen/nav_header_vertical_spacing"
android:paddingTop="4dp"
android:text="@string/nav_header_title"
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:textColor="@color/white"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:id="@+id/textViewSubtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/nav_header_subtitle" />
android:text="@string/nav_header_subtitle"
android:textColor="@color/background_light"
android:textSize="14sp" />
</LinearLayout>

View File

@@ -12,6 +12,14 @@
android:id="@+id/nav_gallery"
android:icon="@drawable/ic_menu_gallery"
android:title="@string/menu_gallery" />
<item
android:id="@+id/nav_live_games"
android:icon="@android:drawable/ic_menu_view"
android:title="@string/menu_live_games" />
<item
android:id="@+id/nav_clubs"
android:icon="@android:drawable/ic_menu_my_calendar"
android:title="@string/menu_clubs" />
<item
android:id="@+id/nav_definicoes"
android:icon="@android:drawable/ic_menu_preferences"

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

View File

@@ -22,4 +22,60 @@
android:name="com.example.vdcscore.ui.definicoes.DefinicoesFragment"
android:label="@string/menu_definicoes"
tools:layout="@layout/fragment_definicoes" />
<fragment
android:id="@+id/nav_live_games"
android:name="com.example.vdcscore.ui.livegames.LiveGamesFragment"
android:label="@string/menu_live_games"
tools:layout="@layout/fragment_live_games">
<action
android:id="@+id/action_nav_live_games_to_nav_live_game_detail"
app:destination="@id/nav_live_game_detail" />
</fragment>
<fragment
android:id="@+id/nav_live_game_detail"
android:name="com.example.vdcscore.ui.livegames.LiveGameDetailFragment"
android:label="@string/title_live_game_detail"
tools:layout="@layout/fragment_live_game_detail" />
<fragment
android:id="@+id/nav_clubs"
android:name="com.example.vdcscore.ui.clubs.ClubsFragment"
android:label="@string/menu_clubs"
tools:layout="@layout/fragment_clubs">
<action
android:id="@+id/action_nav_clubs_to_nav_club_detail"
app:destination="@id/nav_club_detail" />
</fragment>
<fragment
android:id="@+id/nav_club_detail"
android:name="com.example.vdcscore.ui.clubs.ClubDetailFragment"
android:label="Detalhes do Clube"
tools:layout="@layout/fragment_club_detail">
<argument
android:name="clubId"
app:argType="string" />
<argument
android:name="escalao"
app:argType="string" />
<action
android:id="@+id/action_nav_club_detail_to_nav_club_players"
app:destination="@id/nav_club_players" />
</fragment>
<fragment
android:id="@+id/nav_club_players"
android:name="com.example.vdcscore.ui.clubs.ClubPlayersFragment"
android:label="Jogadores"
tools:layout="@layout/fragment_club_players">
<argument
android:name="clubId"
app:argType="string" />
<argument
android:name="escalao"
app:argType="string" />
</fragment>
</navigation>

View File

@@ -1,7 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:tools="http://schemas.android.com/tools">
<!-- Base application theme. -->
<style name="Base.Theme.VdcScore" parent="Theme.Material3.DayNight.NoActionBar">
<!-- Customize your dark theme here. -->
<!-- <item name="colorPrimary">@color/my_dark_primary</item> -->
<!-- Force White Status Bar even in Dark Mode -->
<item name="android:statusBarColor">@color/white</item>
<item name="android:windowLightStatusBar">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
<item name="colorPrimary">@color/primary_color</item>
<item name="colorPrimaryVariant">@color/primary_dark</item>
<item name="colorOnPrimary">@color/white</item>
<item name="colorSecondary">@color/secondary_color</item>
<item name="colorSecondaryVariant">@color/secondary_dark</item>
<item name="colorOnSecondary">@color/white</item>
</style>
<style name="Theme.VdcScore" parent="Base.Theme.VdcScore" />
<style name="Theme.VdcScore.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<!-- Explicitly enforce status bar settings here too -->
<item name="android:statusBarColor">@color/white</item>
<item name="android:windowLightStatusBar">true</item>
<item name="android:windowDrawsSystemBarBackgrounds">true</item>
</style>
</resources>

Some files were not shown because too many files have changed in this diff Show More