Update app.py
Browse files
app.py
CHANGED
|
@@ -1,19 +1,70 @@
|
|
| 1 |
import streamlit as st
|
|
|
|
| 2 |
import folium
|
| 3 |
from streamlit_folium import st_folium
|
|
|
|
| 4 |
|
| 5 |
-
|
| 6 |
-
st.
|
| 7 |
|
| 8 |
-
|
| 9 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 15 |
|
| 16 |
-
#
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
import streamlit as st
|
| 2 |
+
import pandas as pd
|
| 3 |
import folium
|
| 4 |
from streamlit_folium import st_folium
|
| 5 |
+
from datetime import datetime
|
| 6 |
|
| 7 |
+
# --- CONFIG & STYLING ---
|
| 8 |
+
st.set_page_config(page_title="Maldives Vessel Tracker", layout="wide")
|
| 9 |
|
| 10 |
+
st.markdown("""
|
| 11 |
+
<style>
|
| 12 |
+
.main { background-color: #f0f2f6; }
|
| 13 |
+
.stButton>button { width: 100%; border-radius: 20px; background-color: #0077B6; color: white; }
|
| 14 |
+
</style>
|
| 15 |
+
""", unsafe_allow_html=True)
|
| 16 |
|
| 17 |
+
# --- MOCK DATA (Simulating followme.mv) ---
|
| 18 |
+
# In a real app, you would use 'requests' and 'BeautifulSoup' to scrape live data
|
| 19 |
+
data = {
|
| 20 |
+
"Vessel Name": ["Aanu Quick", "Coral Express", "Aagalaa", "Dhon Hiri", "Altec Dash"],
|
| 21 |
+
"Type": ["Speedboat", "Ferry", "Supply Boat", "Dhoni", "Speedboat"],
|
| 22 |
+
"Status": ["Live: On Time", "Delayed", "Scheduled", "Live: On Time", "Live: On Time"],
|
| 23 |
+
"Lat": [4.1755, 4.1910, 4.1700, 4.2100, 4.1850],
|
| 24 |
+
"Lon": [73.5093, 73.5200, 73.5000, 73.5350, 73.5150],
|
| 25 |
+
"Speed": ["31.0 knots", "12.0 knots", "8.5 knots", "22.0 knots", "35.0 knots"]
|
| 26 |
+
}
|
| 27 |
+
df = pd.DataFrame(data)
|
| 28 |
|
| 29 |
+
# --- SIDEBAR: SEARCH & FILTERS ---
|
| 30 |
+
st.sidebar.header("π’ Vessel Finder")
|
| 31 |
+
search_query = st.sidebar.text_input("Search vessel name...", "")
|
| 32 |
+
filter_type = st.sidebar.multiselect("Vessel Type", options=df["Type"].unique(), default=df["Type"].unique())
|
| 33 |
+
|
| 34 |
+
# Filter Logic
|
| 35 |
+
filtered_df = df[(df["Vessel Name"].str.contains(search_query, case=False)) & (df["Type"].isin(filter_type))]
|
| 36 |
+
|
| 37 |
+
# --- MAIN UI ---
|
| 38 |
+
st.title("π Maldives Vessel Management")
|
| 39 |
+
st.write(f"Updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
| 40 |
+
|
| 41 |
+
col1, col2 = st.columns([2, 1])
|
| 42 |
+
|
| 43 |
+
with col1:
|
| 44 |
+
st.subheader("π Live Tracking Map")
|
| 45 |
+
# Create Folium Map (Dark Theme for Gen Z aesthetic)
|
| 46 |
+
m = folium.Map(location=[4.1755, 73.5093], zoom_start=13, tiles="cartodbpositron")
|
| 47 |
+
|
| 48 |
+
for _, row in filtered_df.iterrows():
|
| 49 |
+
color = "green" if "On Time" in row["Status"] else "red"
|
| 50 |
+
folium.Marker(
|
| 51 |
+
location=[row["Lat"], row["Lon"]],
|
| 52 |
+
popup=f"{row['Vessel Name']} ({row['Speed']})",
|
| 53 |
+
icon=folium.Icon(color=color, icon="ship", prefix="fa")
|
| 54 |
+
).add_to(m)
|
| 55 |
+
|
| 56 |
+
st_folium(m, width=800, height=500)
|
| 57 |
+
|
| 58 |
+
with col2:
|
| 59 |
+
st.subheader("π³ Fast Payment (50 MVR)")
|
| 60 |
+
if not filtered_df.empty:
|
| 61 |
+
selected_vessel = st.selectbox("Select Vessel to Pay", filtered_df["Vessel Name"])
|
| 62 |
+
if st.button(f"Pay for {selected_vessel}"):
|
| 63 |
+
st.balloons()
|
| 64 |
+
st.success(f"Payment for {selected_vessel} successful! Check your SMS for the ticket. π«")
|
| 65 |
+
else:
|
| 66 |
+
st.warning("No vessels found matching your search.")
|
| 67 |
+
|
| 68 |
+
# --- DATA TABLE ---
|
| 69 |
+
st.subheader("π Vessel Status Board")
|
| 70 |
+
st.dataframe(filtered_df[["Vessel Name", "Type", "Status", "Speed"]], use_container_width=True)
|