Files
aquilasoft/home.py
2025-11-24 14:24:46 +02:00

469 lines
19 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import flet as ft
from mail import send_gmail
class Home:
def __init__(self, page: ft.Page):
self.page = page
self.web_apps_section = ft.Container(
content=ft.Column(
controls=[
ft.Icon(ft.Icons.WEB, size=34),
ft.Text("Aplicații web", size=18, weight=ft.FontWeight.BOLD),
ft.Text(
"Dashboarduri, aplicații interne, panouri de administrare și soluții de prezentare pentru afacerea ta.",
size=14,
color=ft.Colors.BLUE_GREY_700,
),
],
spacing=10,
),
padding=20,
border_radius=16,
bgcolor=ft.Colors.WHITE,
shadow=ft.BoxShadow(
blur_radius=16,
spread_radius=1,
color=ft.Colors.with_opacity(0.08, ft.Colors.BLUE_GREY_900),
),
width=300
)
self.mobile_apps_section = ft.Container(
content=ft.Column(
controls=[
ft.Icon(ft.Icons.PHONE_ANDROID, size=34),
ft.Text("Aplicații mobile", size=18, weight=ft.FontWeight.BOLD),
ft.Text(
"Aplicații Android și iOS pentru clienți sau angajați, sincronizate cu serverul tău.",
size=14,
color=ft.Colors.BLUE_GREY_700,
),
],
spacing=10,
),
padding=20,
border_radius=16,
bgcolor=ft.Colors.WHITE,
shadow=ft.BoxShadow(
blur_radius=16,
spread_radius=1,
color=ft.Colors.with_opacity(0.08, ft.Colors.BLUE_GREY_900),
),
width=300
)
self.api_section = ft.Container(
content=ft.Column(
controls=[
ft.Icon(ft.Icons.INTEGRATION_INSTRUCTIONS, size=34),
ft.Text("Integrare & automatizare", size=18, weight=ft.FontWeight.BOLD),
ft.Text(
"Integrare cu APIuri de plăți, curieri, facturare, notificări și alte servicii esențiale.",
size=14,
color=ft.Colors.BLUE_GREY_700,
),
],
spacing=10,
),
padding=20,
border_radius=16,
bgcolor=ft.Colors.WHITE,
shadow=ft.BoxShadow(
blur_radius=16,
spread_radius=1,
color=ft.Colors.with_opacity(0.08, ft.Colors.BLUE_GREY_900),
),
width=300
)
self.page.on_resize = self.on_resize
self.error_message = ft.Text()
self.name = ft.TextField(
label="Nume",
col=6,
)
self.email = ft.TextField(
label="Adresă de email",
col=6,
)
self.message = ft.TextField(
label="Mesaj",
multiline=True,
min_lines=3,
max_lines=5,
col=12,
)
def on_resize(self, e):
self.page.update()
def _hero_section(self):
return ft.Container(
content=ft.Row(
[
ft.Column(
[
ft.Text(
"AquilaSoft",
size=42,
weight=ft.FontWeight.BOLD,
color=ft.Colors.BLUE_GREY_900,
),
ft.Row(
controls=[
ft.ElevatedButton(
"Vezi serviciile",
icon=ft.Icons.ROCKET_LAUNCH_OUTLINED,
on_click=lambda e: self.page.scroll_to(key="services_section", duration=500),
),
ft.OutlinedButton(
"Contactează-ne",
icon=ft.Icons.EMAIL_OUTLINED,
on_click=lambda e: self.page.scroll_to(key="contact_section", duration=500),
),
],
spacing=10,
),
ft.Row(
[
ft.Text(
"Aplicații custom, integrate, construite cu Python, Flutter și tehnologii moderne.",
size=14,
color=ft.Colors.BLUE_GREY_500,
),
], alignment=ft.MainAxisAlignment.CENTER
)
]
),
ft.Container(
content=ft.Image(
src="images/logo.png",
width=220,
fit=ft.ImageFit.CONTAIN,
),
padding=20,
border_radius=20,
bgcolor=ft.Colors.WHITE,
shadow=ft.BoxShadow(
blur_radius=25,
spread_radius=1,
color=ft.Colors.with_opacity(0.15, ft.Colors.BLUE_GREY_900),
),
)
],
alignment=ft.MainAxisAlignment.CENTER
)
if self.page.width > 900 else ft.Column(
[
ft.Container(
content=ft.Image(
src="images/logo.png",
width=220,
fit=ft.ImageFit.CONTAIN,
),
padding=20,
border_radius=20,
bgcolor=ft.Colors.WHITE,
shadow=ft.BoxShadow(
blur_radius=25,
spread_radius=1,
color=ft.Colors.with_opacity(0.15, ft.Colors.BLUE_GREY_900),
),
),
ft.Column(
[
ft.Row(
controls=[
ft.ElevatedButton(
"Vezi serviciile",
icon=ft.Icons.ROCKET_LAUNCH_OUTLINED,
on_click=lambda e: self.page.scroll_to(key="services_section", duration=500),
),
ft.OutlinedButton(
"Contactează-ne",
icon=ft.Icons.EMAIL_OUTLINED,
on_click=lambda e: self.page.scroll_to(key="contact_section", duration=500),
),
],
spacing=10,
alignment=ft.MainAxisAlignment.CENTER
),
ft.Row(
[
ft.Text(
"Aplicații custom, integrate, construite cu Python, Flutter și tehnologii moderne."
if self.page.width > 500 else "Aplicații custom, integrate, \nconstruite cu Python, \nFlutter și tehnologii moderne.",
size=14,
color=ft.Colors.BLUE_GREY_500,
text_align=ft.TextAlign.CENTER,
)
],
alignment=ft.MainAxisAlignment.CENTER,
expand=True
)
]
),
],
horizontal_alignment=ft.CrossAxisAlignment.CENTER
),
bgcolor=ft.Colors.WHITE,
padding=10
)
def _section_title(self, title: str, subtitle: str | None = None) -> ft.Control:
return ft.Column(
controls=[
ft.Text(title, size=28, weight=ft.FontWeight.BOLD),
ft.Text(subtitle, size=15, color=ft.Colors.BLUE_GREY_900, text_align=ft.TextAlign.CENTER) if subtitle else ft.Container(),
],
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
spacing=5,
)
def _about_section(self) -> ft.Control:
return ft.Row(
[
ft.Container(
content=ft.Column(
controls=[
self._section_title(
"Cine este AquilaSoft?",
"Suntem un studio de software, cu accent pe calitate, simplitate și soluții gândite pentru oameni ocupați.",
),
ft.Text(
"AquilaSoft este partenerul tău pentru aplicații personalizate. De la management intern și automatizări, până la prezentări online și module integrate în soluțiile existente, construim software adaptat exact modului în care lucrezi tu.",
size=15,
text_align=ft.TextAlign.CENTER,
),
],
spacing=20,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
),
padding=ft.padding.only(top=20, bottom=20),
width=900 if self.page.width > 900 else self.page.width-50
)
],
alignment=ft.MainAxisAlignment.CENTER
)
def _services_section(self) -> ft.Control:
return ft.Column(
controls=[
self._section_title("Ce putem face pentru tine?"),
ft.Row(
[
self.web_apps_section,
self.mobile_apps_section,
self.api_section
],
alignment=ft.MainAxisAlignment.CENTER,
expand=True
),
],
spacing=25,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
expand=True,
key="services_section",
) if self.page.width > 900 else ft.Column(
controls=[
self._section_title("Ce putem face pentru tine?"),
ft.Column(
[
self.web_apps_section,
self.mobile_apps_section,
self.api_section
],
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
expand=True
),
],
spacing=25,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
expand=True,
key="services_section",
)
def _technologies_section(self) -> ft.Control:
tech_chips = ["Python","Flask","Flet","Flutter"] if self.page.width > 900 else ["Python","Flask","Flet"]
tech_chips2 = ["Docker","PostgreSQL / MariaDB","Linux server"] if self.page.width > 900 else ["Flutter", "Docker"]
tech_chips3 = [] if self.page.width > 900 else ["PostgreSQL / MariaDB","Linux server"]
return ft.Container(
content=ft.Column(
controls=[
self._section_title("Tehnologii", "Construim pe un stack modern, stabil și ușor de întreținut."),
ft.Column(
controls=[
ft.Row(
[
ft.Chip(label=ft.Text(t)) for t in tech_chips
],
alignment=ft.MainAxisAlignment.CENTER
),
ft.Row(
[
ft.Chip(label=ft.Text(t)) for t in tech_chips2
],
alignment=ft.MainAxisAlignment.CENTER
),
ft.Row(
[
ft.Chip(label=ft.Text(t)) for t in tech_chips3
],
alignment=ft.MainAxisAlignment.CENTER
),
],
spacing=10,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
expand=True
),
],
spacing=20,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
expand=True
),
padding=ft.padding.only(top=20, bottom=20),
bgcolor=ft.Colors.WHITE,
expand=True
)
def _portfolio_teaser_section(self) -> ft.Control:
return ft.Row(
[
ft.Container(
content=ft.Column(
controls=[
self._section_title("Proiecte & experiență"),
ft.Text(
"Lucrăm la aplicații de gestiune, programări medicale, management transport și magazine online. "
"Siteul de prezentare va include în curând studii de caz și exemple concrete.",
size=15,
text_align=ft.TextAlign.CENTER,
color=ft.Colors.BLUE_GREY_700,
),
],
spacing=15,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
),
padding=ft.padding.only(top=20, bottom=20),
width=900 if self.page.width > 900 else self.page.width-50,
)
],
alignment=ft.MainAxisAlignment.CENTER
)
def _contact_section(self) -> ft.Control:
return ft.Row(
[
ft.Container(
content=ft.Column(
controls=[
self._section_title("Hai să vorbim"),
ft.Text(
"Spune-ne pe scurt ce ai nevoie o aplicație nouă, un modul pentru un sistem existent sau o idee la început de drum.",
size=15,
text_align=ft.TextAlign.CENTER,
),
ft.Container(height=10),
ft.ResponsiveRow(
controls=[
self.name,
self.email,
self.message,
ft.Row(
[
self.error_message
]
),
ft.Container(
content=ft.ElevatedButton(
"Trimite mesajul",
icon=ft.Icons.SEND,
on_click=self.on_send_message_btn_click, # de conectat la backend
),
alignment=ft.alignment.center,
col=12,
padding=ft.padding.only(top=10),
),
],
columns=12,
run_spacing=10,
),
],
spacing=20,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
),
padding=ft.padding.only(top=30, bottom=30),
width=900 if self.page.width > 900 else self.page.width-50,
key="contact_section",
)
],
alignment=ft.MainAxisAlignment.CENTER
)
def _footer_section(self) -> ft.Control:
return ft.Container(
content=ft.Column(
controls=[
ft.Divider(),
ft.Text(
"© " + "2026" + " AquilaSoft. Toate drepturile rezervate.",
size=12,
color=ft.Colors.BLUE_GREY_500,
text_align=ft.TextAlign.CENTER,
),
ft.Text(
"Creat cu pasiune, Python și un strop de cafea.",
size=12,
color=ft.Colors.BLUE_GREY_400,
text_align=ft.TextAlign.CENTER,
),
],
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
),
padding=ft.padding.only(bottom=10, top=-7),
bgcolor=ft.Colors.WHITE
)
def on_send_message_btn_click(self, e):
name = self.name.value
email = self.email.value
message = self.message.value
found = False
if name is None or len(name)< 2:
found = True
if email is None or len(email)< 2:
found = True
if message is None or len(message)< 2:
found = True
if not found:
send_gmail('macamete.robert@gmail.com', 'Contact nou pe Aquila Soft', email+'\n'+message)
self.error_message.value = "Mesajul a fost trimis cu succes! \nVeți fi contactat în curând de unul dintre colegii noștri."
self.error_message.color = ft.Colors.GREEN
self.error_message.update()
else:
self.error_message.value = "Toate campurile sunt obligatori!"
self.error_message.color = ft.Colors.RED
self.error_message.update()
def build(self):
return ft.Container(
content=ft.Column(
[
self._hero_section(),
self._about_section(),
self._services_section(),
self._technologies_section(),
self._portfolio_teaser_section(),
self._contact_section(),
self._footer_section()
],
scroll=ft.ScrollMode.ADAPTIVE,
expand=True,
),
expand=True
)