first commit

This commit is contained in:
2025-11-24 13:17:06 +02:00
commit b7deb9cb0a
10 changed files with 633 additions and 0 deletions

BIN
assets/.DS_Store vendored Normal file

Binary file not shown.

BIN
assets/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
assets/icons/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

BIN
assets/images/.DS_Store vendored Normal file

Binary file not shown.

BIN
assets/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

469
home.py Normal file
View File

@@ -0,0 +1,469 @@
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
)

139
mail.py Normal file
View File

@@ -0,0 +1,139 @@
import smtplib
from email.message import EmailMessage
import os
def send_email(to_email, subject, body):
smtp_host = os.environ.get("SMTP_HOST")
smtp_port = int(os.environ.get("SMTP_PORT", 587))
smtp_user = os.environ.get("SMTP_USER")
smtp_pass = os.environ.get("SMTP_PASS")
sender_email = os.environ.get("SMTP_FROM", smtp_user)
if not all([smtp_host, smtp_port, smtp_user, smtp_pass]):
raise ValueError("SMTP config incomplete in environment variables.")
msg = EmailMessage()
msg["Subject"] = subject
msg["From"] = sender_email
msg["To"] = to_email
msg.set_content(body)
with smtplib.SMTP(smtp_host, smtp_port) as server:
server.starttls()
server.login(smtp_user, smtp_pass)
server.send_message(msg)
# Send email with attachment
def send_email_with_attachment(to_email, subject, body, attachment_path):
smtp_host = os.environ.get("SMTP_HOST")
smtp_port = int(os.environ.get("SMTP_PORT", 587))
smtp_user = os.environ.get("SMTP_USER")
smtp_pass = os.environ.get("SMTP_PASS")
sender_email = os.environ.get("SMTP_FROM", smtp_user)
if not all([smtp_host, smtp_port, smtp_user, smtp_pass]):
raise ValueError("SMTP config incomplete in environment variables.")
msg = EmailMessage()
msg["Subject"] = subject
msg["From"] = sender_email
msg["To"] = to_email
msg.set_content(body)
if attachment_path and os.path.isfile(attachment_path):
with open(attachment_path, "rb") as f:
file_data = f.read()
file_name = os.path.basename(attachment_path)
msg.add_attachment(file_data, maintype="application", subtype="pdf", filename=file_name)
else:
raise FileNotFoundError(f"Attachment file not found: {attachment_path}")
with smtplib.SMTP(smtp_host, smtp_port) as server:
server.starttls()
server.login(smtp_user, smtp_pass)
server.send_message(msg)
# Send email using Gmail directly
def send_gmail(to_email, subject, body):
smtp_host = "smtp.gmail.com"
smtp_port = 587
smtp_user = 'macamete.robert@gmail.com'
smtp_pass = 'advx yqlv jkaa czvr'
sender_email = 'macamete.robert@gmail.com'
if not all([smtp_user, smtp_pass]):
raise ValueError("GMAIL_USER and GMAIL_PASS must be set in environment variables.")
msg = EmailMessage()
msg["Subject"] = subject
msg["From"] = sender_email
msg["To"] = to_email
msg.set_content(body)
with smtplib.SMTP(smtp_host, smtp_port) as server:
server.starttls()
server.login(smtp_user, smtp_pass)
server.send_message(msg)
# Send email with attachment using Gmail directly
def send_gmail_with_attachment(to_email, subject, body, attachment_path):
smtp_host = "smtp.gmail.com"
smtp_port = 587
smtp_user = 'macamete.robert@gmail.com'
smtp_pass = 'advx yqlv jkaa czvr'
sender_email = 'macamete.robert@gmail.com'
if not all([smtp_user, smtp_pass]):
raise ValueError("GMAIL_USER and GMAIL_PASS must be set in environment variables.")
msg = EmailMessage()
msg["Subject"] = subject
msg["From"] = sender_email
msg["To"] = to_email
msg.set_content(body)
if attachment_path and os.path.isfile(attachment_path):
with open(attachment_path, "rb") as f:
file_data = f.read()
file_name = os.path.basename(attachment_path)
msg.add_attachment(file_data, maintype="application", subtype="pdf", filename=file_name)
else:
raise FileNotFoundError(f"Attachment file not found: {attachment_path}")
with smtplib.SMTP(smtp_host, smtp_port) as server:
server.starttls()
server.login(smtp_user, smtp_pass)
server.send_message(msg)
# Send email with attachment
def send_custom_email_with_attachment(to_email, subject, body, attachment_path, SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS):
smtp_host = SMTP_HOST
smtp_port = int(SMTP_PORT)
smtp_user = SMTP_USER
smtp_pass = SMTP_PASS
sender_email = smtp_user
if not all([smtp_host, smtp_port, smtp_user, smtp_pass]):
raise ValueError("SMTP config incomplete in environment variables.")
msg = EmailMessage()
msg["Subject"] = subject
msg["From"] = sender_email
msg["To"] = to_email
msg.set_content(body)
if attachment_path and os.path.isfile(attachment_path):
with open(attachment_path, "rb") as f:
file_data = f.read()
file_name = os.path.basename(attachment_path)
msg.add_attachment(file_data, maintype="application", subtype="pdf", filename=file_name)
else:
raise FileNotFoundError(f"Attachment file not found: {attachment_path}")
with smtplib.SMTP(smtp_host, smtp_port) as server:
server.starttls()
server.login(smtp_user, smtp_pass)
server.send_message(msg)

25
main.py Normal file
View File

@@ -0,0 +1,25 @@
import flet as ft
from home import Home
def main(page: ft.Page):
page.title = 'AquilaSoft'
page.theme = ft.Theme(color_scheme_seed=ft.Colors.BLUE)
page.horizontal_alignment = ft.CrossAxisAlignment.CENTER
page.vertical_alignment = ft.MainAxisAlignment.CENTER
page.theme_mode = ft.ThemeMode.LIGHT
page.padding = 0
def route_change(route):
page.controls.clear()
if "/" == route:
home = Home(page)
page.add(home.build())
page.update()
page.on_route_change = lambda _: route_change(page.route)
page.go('/')
ft.app(target=main, assets_dir="assets", view=ft.WEB_BROWSER, port='8550')