From 5c2f19dcc469b5b21d4d7ad3a7e578757f4e5d2d Mon Sep 17 00:00:00 2001 From: yaso Date: Tue, 10 Feb 2026 11:58:35 +0200 Subject: [PATCH 01/31] enable linux platform & rename widnow --- mih_ui/linux/my_application.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mih_ui/linux/my_application.cc b/mih_ui/linux/my_application.cc index 8758cffa..8f518d2d 100644 --- a/mih_ui/linux/my_application.cc +++ b/mih_ui/linux/my_application.cc @@ -40,11 +40,11 @@ static void my_application_activate(GApplication* application) { if (use_header_bar) { GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "patient_manager"); + gtk_header_bar_set_title(header_bar, "MIH App - Mzansi Innovation Hub"); gtk_header_bar_set_show_close_button(header_bar, TRUE); gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); } else { - gtk_window_set_title(window, "patient_manager"); + gtk_window_set_title(window, "MIH App - Mzansi Innovation Hub"); } gtk_window_set_default_size(window, 1280, 720); From 91075255f4a153348c0296da2ec1d2c7ddbd9d0f Mon Sep 17 00:00:00 2001 From: yaso Date: Tue, 10 Feb 2026 14:07:05 +0200 Subject: [PATCH 02/31] add scrolling to about package --- .../main/res/drawable/mzansi_directory.xml | 3 +- .../mih_single_child_scroll.dart | 5 +- .../package_tools/mih_ attributes.dart | 348 +++++++++--------- .../about_mih/package_tools/mih_info.dart | 1 + .../package_tools/mih_privacy_policy.dart | 11 +- .../package_tools/mih_terms_of_service.dart | 9 +- 6 files changed, 195 insertions(+), 182 deletions(-) diff --git a/mih_ui/android/app/src/main/res/drawable/mzansi_directory.xml b/mih_ui/android/app/src/main/res/drawable/mzansi_directory.xml index 5cd49d32..1ee03963 100644 --- a/mih_ui/android/app/src/main/res/drawable/mzansi_directory.xml +++ b/mih_ui/android/app/src/main/res/drawable/mzansi_directory.xml @@ -5,7 +5,6 @@ android:height="23.53125dp" android:width="24dp"> + android:fillColor="@color/mih_icon_foreground"/> diff --git a/mih_ui/lib/mih_package_components/mih_single_child_scroll.dart b/mih_ui/lib/mih_package_components/mih_single_child_scroll.dart index f8f6e096..74c846b1 100644 --- a/mih_ui/lib/mih_package_components/mih_single_child_scroll.dart +++ b/mih_ui/lib/mih_package_components/mih_single_child_scroll.dart @@ -2,9 +2,11 @@ import 'package:flutter/material.dart'; class MihSingleChildScroll extends StatefulWidget { final Widget child; + final bool? scrollbarOn; const MihSingleChildScroll({ super.key, required this.child, + this.scrollbarOn, }); @override @@ -18,7 +20,8 @@ class _MihSingleChildScrollState extends State { bottom: false, minimum: EdgeInsets.only(bottom: 5), child: ScrollConfiguration( - behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false), + behavior: ScrollConfiguration.of(context) + .copyWith(scrollbars: widget.scrollbarOn ?? false), child: SingleChildScrollView( child: widget.child, ), diff --git a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_ attributes.dart b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_ attributes.dart index abdbff56..d1948fef 100644 --- a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_ attributes.dart +++ b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_ attributes.dart @@ -94,7 +94,6 @@ class _MihAttributesState extends State { Widget build(BuildContext context) { return MihPackageToolBody( borderOn: false, - innerHorizontalPadding: 10, bodyItem: getBody(), ); } @@ -108,179 +107,184 @@ class _MihAttributesState extends State { "As per the terms for free use for these third party providers, the following assets require attribution"; return MihSingleChildScroll( - child: Column( - children: [ - Icon( - MihIcons.mihLogo, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - size: 165, - ), - const SizedBox( - height: 10, - ), - SelectableText( - message, - style: const TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, + scrollbarOn: true, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Column( + children: [ + Icon( + MihIcons.mihLogo, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + size: 165, ), - ), - const SizedBox( - height: 10, - ), - SizedBox( - width: 700, - child: Table( - defaultVerticalAlignment: TableCellVerticalAlignment.middle, - columnWidths: const { - 0: FlexColumnWidth(1), - 1: FlexColumnWidth(1), - 2: FlexColumnWidth(1), - }, - children: [ - const TableRow( - children: [ - TableCell( - verticalAlignment: TableCellVerticalAlignment.middle, - child: Padding( - padding: const EdgeInsets.only(bottom: 15.0), - child: Center( - child: Text( - "Resources", - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), - TableCell( - verticalAlignment: TableCellVerticalAlignment.middle, - child: Padding( - padding: const EdgeInsets.only(bottom: 15.0), - child: Center( - child: Text( - "Creator", - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), - TableCell( - child: Padding( - padding: const EdgeInsets.only(bottom: 15.0), - child: Center( - child: Text( - "Link", - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), - ], - ), - displayIcon(MihIcons.mihRing, "Tarah Meth", - "https://www.linkedin.com/in/tarah-meth-3b6309254/"), - displayIcon(MihIcons.mihLogo, "Tarah Meth", - "https://www.linkedin.com/in/tarah-meth-3b6309254/"), - displayIcon(MihIcons.mzansiAi, "Ollama", "https://ollama.com/"), - displayIcon(MihIcons.mzansiWallet, "Freepik", - "https://www.flaticon.com/free-icon/wallet-passes-app_3884407?term=wallet&page=1&position=21&origin=search&related_id=3884407"), - displayIcon(MihIcons.patientProfile, "RaftelDesign", - "https://www.flaticon.com/free-icon/patient_2376100?term=medication&page=1&position=6&origin=search&related_id=2376100"), - displayIcon(MihIcons.patientProfile, "Srip", - "https://www.flaticon.com/free-icon/hospital_1233930?term=medical+snake&page=1&position=7&origin=search&related_id=1233930"), - displayIcon(MihIcons.calendar, "Freepik", - "https://www.flaticon.com/free-icon/calendar_2278049?term=calendar&page=1&position=5&origin=search&related_id=2278049"), - displayIcon(MihIcons.calculator, "Freepik", - "https://www.flaticon.com/free-icon/calculator_2374409?term=calculator&page=1&position=20&origin=search&related_id=2374409"), - displayIcon(MihIcons.aboutMih, "Chanut", - "https://www.flaticon.com/free-icon/info_151776?term=about&page=1&position=8&origin=search&related_id=151776"), - displayIcon(MihIcons.personalProfile, "Freepik", - "https://www.flaticon.com/free-icon/user_1077063?term=profile&page=1&position=6&origin=search&related_id=1077063"), - displayIcon(MihIcons.businessProfile, "Gravisio", - "https://www.flaticon.com/free-icon/contractor_11813336?term=company+profile&page=1&position=2&origin=search&related_id=11813336"), - displayIcon(MihIcons.patientManager, "Vector Tank", - "https://www.flaticon.com/free-icon/doctor_10215061?term=doctor&page=1&position=73&origin=search&related_id=10215061"), - displayIcon(MihIcons.profileSetup, "Freepik", - "https://www.flaticon.com/free-icon/add-user_748137?term=profile+add&page=1&position=1&origin=search&related_id=748137"), - displayIcon(MihIcons.businessSetup, "kerismaker", - "https://www.flaticon.com/free-icon/business_13569850?term=company+add&page=1&position=25&origin=search&related_id=13569850"), - displayIcon(MihIcons.calculator, "fawazahmed0", - "https://github.com/fawazahmed0/exchange-api"), - displayIcon(MihIcons.iDontKnow, "Freepik", - "https://www.flaticon.com/free-icon/i-dont-know_5359909?term=i+dont+know&page=1&position=7&origin=search&related_id=5359909"), - ], + const SizedBox( + height: 10, ), - ), - // SizedBox( - // width: 500, - // child: Column( - // children: [ - // const SizedBox( - // width: double.infinity, - // child: Row( - // mainAxisAlignment: MainAxisAlignment.spaceEvenly, - // mainAxisSize: MainAxisSize.max, - // children: [ - // Flexible( - // child: Text( - // "Icon", - // style: TextStyle( - // fontSize: 25, - // fontWeight: FontWeight.bold, - // ), - // ), - // ), - // Flexible( - // child: Text( - // "Creator", - // style: TextStyle( - // fontSize: 25, - // fontWeight: FontWeight.bold, - // ), - // ), - // ), - // Flexible( - // child: Text( - // "Link", - // style: TextStyle( - // fontSize: 25, - // fontWeight: FontWeight.bold, - // ), - // ), - // ), - // ], - // ), - // ), - // const Padding( - // padding: EdgeInsets.symmetric(vertical: 10.0), - // child: Divider(), - // ), - // displayIcon(MihIcons.mihLogo, "Tarah Meth", - // "https://app.mzansi-innovation-hub.co.za/"), - // const SizedBox(height: 10), - // displayIcon(MihIcons.mihLogo, "Test", - // "https://www.flaticon.com/free-icons/mih"), - // const SizedBox(height: 10), - // displayIcon(MihIcons.mihLogo, "Test", - // "https://www.flaticon.com/free-icons/mih"), - // const SizedBox(height: 10), - // displayIcon(MihIcons.mihLogo, "Test", - // "https://www.flaticon.com/free-icons/mih"), - // const SizedBox(height: 10), - // ], - // ), - // ) - ], + SelectableText( + message, + style: const TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox( + height: 10, + ), + SizedBox( + width: 700, + child: Table( + defaultVerticalAlignment: TableCellVerticalAlignment.middle, + columnWidths: const { + 0: FlexColumnWidth(1), + 1: FlexColumnWidth(1), + 2: FlexColumnWidth(1), + }, + children: [ + const TableRow( + children: [ + TableCell( + verticalAlignment: TableCellVerticalAlignment.middle, + child: Padding( + padding: const EdgeInsets.only(bottom: 15.0), + child: Center( + child: Text( + "Resources", + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ), + TableCell( + verticalAlignment: TableCellVerticalAlignment.middle, + child: Padding( + padding: const EdgeInsets.only(bottom: 15.0), + child: Center( + child: Text( + "Creator", + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ), + TableCell( + child: Padding( + padding: const EdgeInsets.only(bottom: 15.0), + child: Center( + child: Text( + "Link", + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ), + ], + ), + displayIcon(MihIcons.mihRing, "Tarah Meth", + "https://www.linkedin.com/in/tarah-meth-3b6309254/"), + displayIcon(MihIcons.mihLogo, "Tarah Meth", + "https://www.linkedin.com/in/tarah-meth-3b6309254/"), + displayIcon( + MihIcons.mzansiAi, "Ollama", "https://ollama.com/"), + displayIcon(MihIcons.mzansiWallet, "Freepik", + "https://www.flaticon.com/free-icon/wallet-passes-app_3884407?term=wallet&page=1&position=21&origin=search&related_id=3884407"), + displayIcon(MihIcons.patientProfile, "RaftelDesign", + "https://www.flaticon.com/free-icon/patient_2376100?term=medication&page=1&position=6&origin=search&related_id=2376100"), + displayIcon(MihIcons.patientProfile, "Srip", + "https://www.flaticon.com/free-icon/hospital_1233930?term=medical+snake&page=1&position=7&origin=search&related_id=1233930"), + displayIcon(MihIcons.calendar, "Freepik", + "https://www.flaticon.com/free-icon/calendar_2278049?term=calendar&page=1&position=5&origin=search&related_id=2278049"), + displayIcon(MihIcons.calculator, "Freepik", + "https://www.flaticon.com/free-icon/calculator_2374409?term=calculator&page=1&position=20&origin=search&related_id=2374409"), + displayIcon(MihIcons.aboutMih, "Chanut", + "https://www.flaticon.com/free-icon/info_151776?term=about&page=1&position=8&origin=search&related_id=151776"), + displayIcon(MihIcons.personalProfile, "Freepik", + "https://www.flaticon.com/free-icon/user_1077063?term=profile&page=1&position=6&origin=search&related_id=1077063"), + displayIcon(MihIcons.businessProfile, "Gravisio", + "https://www.flaticon.com/free-icon/contractor_11813336?term=company+profile&page=1&position=2&origin=search&related_id=11813336"), + displayIcon(MihIcons.patientManager, "Vector Tank", + "https://www.flaticon.com/free-icon/doctor_10215061?term=doctor&page=1&position=73&origin=search&related_id=10215061"), + displayIcon(MihIcons.profileSetup, "Freepik", + "https://www.flaticon.com/free-icon/add-user_748137?term=profile+add&page=1&position=1&origin=search&related_id=748137"), + displayIcon(MihIcons.businessSetup, "kerismaker", + "https://www.flaticon.com/free-icon/business_13569850?term=company+add&page=1&position=25&origin=search&related_id=13569850"), + displayIcon(MihIcons.calculator, "fawazahmed0", + "https://github.com/fawazahmed0/exchange-api"), + displayIcon(MihIcons.iDontKnow, "Freepik", + "https://www.flaticon.com/free-icon/i-dont-know_5359909?term=i+dont+know&page=1&position=7&origin=search&related_id=5359909"), + ], + ), + ), + // SizedBox( + // width: 500, + // child: Column( + // children: [ + // const SizedBox( + // width: double.infinity, + // child: Row( + // mainAxisAlignment: MainAxisAlignment.spaceEvenly, + // mainAxisSize: MainAxisSize.max, + // children: [ + // Flexible( + // child: Text( + // "Icon", + // style: TextStyle( + // fontSize: 25, + // fontWeight: FontWeight.bold, + // ), + // ), + // ), + // Flexible( + // child: Text( + // "Creator", + // style: TextStyle( + // fontSize: 25, + // fontWeight: FontWeight.bold, + // ), + // ), + // ), + // Flexible( + // child: Text( + // "Link", + // style: TextStyle( + // fontSize: 25, + // fontWeight: FontWeight.bold, + // ), + // ), + // ), + // ], + // ), + // ), + // const Padding( + // padding: EdgeInsets.symmetric(vertical: 10.0), + // child: Divider(), + // ), + // displayIcon(MihIcons.mihLogo, "Tarah Meth", + // "https://app.mzansi-innovation-hub.co.za/"), + // const SizedBox(height: 10), + // displayIcon(MihIcons.mihLogo, "Test", + // "https://www.flaticon.com/free-icons/mih"), + // const SizedBox(height: 10), + // displayIcon(MihIcons.mihLogo, "Test", + // "https://www.flaticon.com/free-icons/mih"), + // const SizedBox(height: 10), + // displayIcon(MihIcons.mihLogo, "Test", + // "https://www.flaticon.com/free-icons/mih"), + // const SizedBox(height: 10), + // ], + // ), + // ) + ], + ), ), ); } diff --git a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart index 3260449a..f60e3f7b 100644 --- a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart +++ b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart @@ -777,6 +777,7 @@ class _MihInfoState extends State { return Stack( children: [ MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ aboutHeadings(), diff --git a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_privacy_policy.dart b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_privacy_policy.dart index 0ac7d838..92e4f575 100644 --- a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_privacy_policy.dart +++ b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_privacy_policy.dart @@ -19,7 +19,6 @@ class _MihPrivacyPolicyState extends State { Widget build(BuildContext context) { return MihPackageToolBody( borderOn: false, - innerHorizontalPadding: 10, bodyItem: getBody(context), ); } @@ -55,9 +54,13 @@ class _MihPrivacyPolicyState extends State { children .addAll(PolicyAndTermsText().getPrivacyPolicyText(context, englishOn)); return MihSingleChildScroll( - child: Column( - mainAxisSize: MainAxisSize.max, - children: children, + scrollbarOn: true, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Column( + mainAxisSize: MainAxisSize.max, + children: children, + ), ), ); } diff --git a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_terms_of_service.dart b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_terms_of_service.dart index 4f73ea0e..435b71ea 100644 --- a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_terms_of_service.dart +++ b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_terms_of_service.dart @@ -19,7 +19,6 @@ class _MIHTermsOfServiceState extends State { Widget build(BuildContext context) { return MihPackageToolBody( borderOn: false, - innerHorizontalPadding: 10, bodyItem: getBody(context), ); } @@ -55,8 +54,12 @@ class _MIHTermsOfServiceState extends State { children .addAll(PolicyAndTermsText().getTermsOfServiceText(context, englishOn)); return MihSingleChildScroll( - child: Column( - children: children, + scrollbarOn: true, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 10.0), + child: Column( + children: children, + ), ), ); } From 7d4d7fc713c4fea1b325a52ac13fce7752cce976 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 4 Feb 2026 15:04:23 +0200 Subject: [PATCH 03/31] BUG: Fix Security Flutter Web server --- .DS_Store | Bin 8196 -> 8196 bytes mih_ui/Dockerfile | 58 +++++++++++++------------------- mih_ui/server/MIH_web_server.py | 30 ----------------- mih_ui/server/server.sh | 18 ---------- 4 files changed, 23 insertions(+), 83 deletions(-) delete mode 100644 mih_ui/server/MIH_web_server.py delete mode 100644 mih_ui/server/server.sh diff --git a/.DS_Store b/.DS_Store index bb29be065bc104344337a20e9e6fccb5ffccb05c..e07f5f73ca0afb8cb8599399826546c90f05d453 100644 GIT binary patch delta 60 zcmZp1XmOa}&nUMsU^hRb+-4qu^Nf;g47m)M3>ggZ45bX2Wx+*xIr(|%3=9m6n{NmT Qvu$RV_{OsNp$I!O01fRCHvj+t delta 40 wcmZp1XmOa}&nUYwU^hRb>}DQ;^NgFn3ktAJERfmEF7b_Jv!v)drilfT02sOrvj6}9 diff --git a/mih_ui/Dockerfile b/mih_ui/Dockerfile index 1664c3c1..fe4435fc 100644 --- a/mih_ui/Dockerfile +++ b/mih_ui/Dockerfile @@ -1,48 +1,36 @@ -# Install Operating system and dependencies -#FROM ubuntu:22.04 +# --- STAGE 1: The Builder --- FROM debian:latest AS build-env -#ENV DEBIAN_FRONTEND=noninteractive +# Install necessary dependencies for Flutter +RUN apt-get update && apt-get install -y \ + curl git wget unzip libglu1-mesa fonts-droid-fallback python3 \ + && rm -rf /var/lib/apt/lists/* -RUN apt-get update --fix-missing - -RUN apt-get install -y curl git wget unzip gdb libstdc++6 libglu1-mesa fonts-droid-fallback -# RUN apt-get install -y curl git wget unzip libgconf-2-4 gdb libstdc++6 libglu1-mesa fonts-droid-fallback -RUN apt-get install python3 -y - -# download Flutter SDK from Flutter Github repo +# Clone Flutter SDK RUN git clone -b flutter-3.32-candidate.0 https://github.com/flutter/flutter.git /usr/local/flutter -# RUN git clone -b stable https://github.com/flutter/flutter.git /usr/local/flutter - -# Set flutter environment path ENV PATH="/usr/local/flutter/bin:/usr/local/flutter/bin/cache/dart-sdk/bin:${PATH}" -#ENV PATH "$PATH:/home/developer/flutter/bin" - -RUN flutter doctor -v - -# Enable flutter web -RUN flutter channel flutter-3.32-candidate.0 -# RUN flutter channel stable -RUN flutter config --enable-web - -# Copy files to container and build -RUN mkdir /app/ -COPY . /app/ +# Build the Flutter web app WORKDIR /app -# RUN flutter upgrade +COPY . . +RUN flutter config --enable-web RUN flutter build web --release -t ./lib/main_prod.dart -# RUN flutter build web --release --web-renderer canvaskit -t ./lib/main_prod.dart +# --- STAGE 2: The Final Production Image --- +FROM nginx:alpine -# RUN cd .. +# Copy built files from the first stage +COPY --from=build-env /app/build/web /usr/share/nginx/html -# WORKDIR /app/build/web/ +# Create the Nginx config inside the Dockerfile to handle SPA routing +RUN echo 'server { \ + listen 83; \ + location / { \ + root /usr/share/nginx/html; \ + index index.html; \ + try_files $uri $uri/ /index.html; \ + } \ + }' > /etc/nginx/conf.d/default.conf EXPOSE 83 - -RUN ["chmod", "+x", "/app/server/server.sh"] - -ENTRYPOINT [ "/app/server/server.sh"] - -# RUN ["python3", "-u", "/app/server/MIH_web_server.py"] \ No newline at end of file +CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/mih_ui/server/MIH_web_server.py b/mih_ui/server/MIH_web_server.py deleted file mode 100644 index c4bd7eb0..00000000 --- a/mih_ui/server/MIH_web_server.py +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env python - -# Inspired by https://gist.github.com/jtangelder/e445e9a7f5e31c220be6 -# Python3 http.server for Single Page Application - -import urllib.parse -import http.server -import socketserver -import re -from pathlib import Path -port = 83 -HOST = ('', port) -pattern = re.compile('.png|.jpg|.jpeg|.js|.css|.ico|.gif|.svg|.ico', re.IGNORECASE) - - -class Handler(http.server.SimpleHTTPRequestHandler): - def do_GET(self): - url_parts = urllib.parse.urlparse(self.path) - request_file_path = Path(url_parts.path.strip("/")) - - ext = request_file_path.suffix - if not request_file_path.is_file() and not pattern.match(ext): - self.path = 'index.html' - - return http.server.SimpleHTTPRequestHandler.do_GET(self) - - -httpd = socketserver.TCPServer(HOST, Handler) -print(f"Starting Web App Server on pot: {port}") -httpd.serve_forever() diff --git a/mih_ui/server/server.sh b/mih_ui/server/server.sh deleted file mode 100644 index 2fb5d8b7..00000000 --- a/mih_ui/server/server.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -# Define the port -PORT=83 - -# Check if the port is in use and release it if necessary. -# echo "Checking if port $PORT is in use..." -# if [ "$(lsof -t -i :$PORT)" ]; then -# echo "Port $PORT is in use. Stopping the process on that port..." -# fuser -k -n tcp $PORT -# fi - -# Switch to the web construction directory -cd /app/build/web/ - -# Start the web server on the specified port -#python3 -m http.server 83 -python3 -u ../../server/MIH_web_server.py \ No newline at end of file From b897986c1ff8d8ff6c0500117c382f88e70bdd1d Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 4 Feb 2026 15:39:47 +0200 Subject: [PATCH 04/31] BUG: Fix hardcoded supertoken api key --- .DS_Store | Bin 8196 -> 10244 bytes docker-compose.yml | 31 ------------------ mih_api_hub/__init__.py | 28 ---------------- mih_api_hub/main.py | 7 +++- mih_ui/.gitignore | 2 ++ mih_ui/lib/main_dev.dart | 2 ++ mih_ui/lib/main_prod.dart | 2 ++ .../package_tools/mih_register.dart | 3 +- .../mih_authentication_services.dart | 3 +- mih_ui/pubspec.lock | 8 +++++ mih_ui/pubspec.yaml | 2 ++ 11 files changed, 26 insertions(+), 62 deletions(-) diff --git a/.DS_Store b/.DS_Store index e07f5f73ca0afb8cb8599399826546c90f05d453..03fe24efd63baf02bcbb1f3f70c3f49648b43260 100644 GIT binary patch literal 10244 zcmeGhTWl0n^qgr6GjwQ&TBTqoE);{3Qrc2z5ir}AQUt2q);_GRyE|h$FgvsE>~4YD zxH0iZ6l46*i1_;PLDYl@K7KS&@$un@qKU?+F=~7yJ`#UaqMmzaww>J;;|DQn<|cE` zz2|Z7x#w~3of!bYuB_Gq5CQ;^9tIVess#$8vu9orJWPlnl029bEs=zsOwHpA5P<~( z3j`JjED%^Au)x2?0(54xB38OEr~?ZG76>dbYXP=Dgy>-~?7_SX`PM-de+3{|PH0}J zt*{2ckO#va%)5{%RL~VA=!&BEih-^;;X@u@*n@c&y5fM|%LjThqxXh_e0CZ?#MuGE zE)43x0)YkQTOdTJa%h4HFd*Z9f3FJvey^XFw0nBurX44oSkwOL@o?`OoyBzRFX^et zxo-p2;~^4-3Ys?uI#`hN&n*3{v}8ABo2%D z{0=0*1`Tw-4gh6O&FApz(bI7(yz@BMqhuVvE@$WR>*MW}HKc`2+Uz5nq+vbRD+wvW zIfQ9~1CRu>&$JVsA84yXm9%X7gBP|WSVTMqOhOd0V3+vP2b#8al>WSW~lLZPg@ zV$otzT2d)5Rfk7L$K>&-Qj;_Ess2>Pur23WJ?#*TD%H-UJ=K@6t*g^IqYo!+Gn=%W zsIn{(GZR@emeD&+Gh!Un30LhT(za<{Z94`VW^^Q@@6RyWJkrRRW2ZCSe6XmZWF37# zr?HHj-a{igBL+>$1Z(+{<|>q)sak%~noHKVwr>mf_U*prbhWaq=Db>29y2uE${05p zdU|Ne&@z*wF(;v0nqf^0=M2Y)oBE&?OX|z8QIbwq*R5E2VZExJjddg&H*U@vnFC6L zDDpW%t5kVhBjtA68kbzb8YEzeur&{9LV*~Qbru0kvHz%ICv z!g?C+g8ShZJO{7CDR>_~fp6dk_yrLcp@d7Y5^HfKuE9p!gzeaYTd)iJ@fsY!2#(_< z8n_o7+>Zxw8gIed@eaHb@4~})A0EYr@ezC!pTgt#9G<|F_%gnUZ{gec9)6Br;FtIn z{(!&YZ+J$i5S9yd!U|!v&?u}InuK=kSw$J_7_ z#rk2q8}Gpf@CZJL58>nZ1jYL?e43*Dd3*t1!dLM%JcVy~asM$z{kQmCNhI$sj%56~ zG?H_Xv}M}X1mRiqSI`m7E(jLvFFt;N9m5a#jvpUqe9G~%0bVF%!v}@KXR%l*ULT>; z#obQ2V(IHxZ_u{Qc%dDOUrT3BRH^N@txU|Ios0|6PERc3!xR|yRF|E#G>6MZT!JWx zQdFs%o^ET|(im#n)H2f;n%>gdOzn-EXJ#bv{Duu%2crATq-Ebh+Ec+ohA(ydv-Kfr z`BqeXL0HS!d{qDCzn4|boz&B8ze2G^i7=T{#Ko9ID*hB}vR^pv! zNkhMPM99!Zf?X+^=+WS&Vt#&^@bi~*eg`roe9SHj^7(xJ;y>>571Pt3nwg(Bw=ti$ zv^H;A$mvXZDra^2okW~nc(Kd5;4IDW@W+&;!=HW6Z-YMioVypI7dyLn>=IXVVo(JZ z2rLj-;G9{Y%pECINwD|q|Nqa~e8E701p*8F`z(OvJ&~R+(yMR}E>)3zYY)+LBR#Az zzPt;$2vz)ZJVE|Bo;vJv{3Y}--ol3f)((5PybB3K { headers: { 'Content-type': 'application/json', 'Accept': 'application/json', - "Authorization": "leatucczyixqwkqqdrhayiwzeofkltds" + "Authorization": dotenv.env['SUPERTOKENS_API_KEY'] ?? "", }, ); //print("response 2: ${response2.statusCode}"); diff --git a/mih_ui/lib/mih_services/mih_authentication_services.dart b/mih_ui/lib/mih_services/mih_authentication_services.dart index 3b1f6cd7..08b59175 100644 --- a/mih_ui/lib/mih_services/mih_authentication_services.dart +++ b/mih_ui/lib/mih_services/mih_authentication_services.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; +import 'package:flutter_dotenv/flutter_dotenv.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_button.dart'; @@ -32,7 +33,7 @@ class MihAuthenticationServices { headers: { 'Content-type': 'application/json', 'Accept': 'application/json', - "Authorization": "leatucczyixqwkqqdrhayiwzeofkltds" + "Authorization": dotenv.env['SUPERTOKENS_API_KEY'] ?? "", }, ); if (response.statusCode == 200) { diff --git a/mih_ui/pubspec.lock b/mih_ui/pubspec.lock index 41003e1b..6c3cdb57 100644 --- a/mih_ui/pubspec.lock +++ b/mih_ui/pubspec.lock @@ -670,6 +670,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.0" + flutter_dotenv: + dependency: "direct main" + description: + name: flutter_dotenv + sha256: d4130c4a43e0b13fefc593bc3961f2cb46e30cb79e253d4a526b1b5d24ae1ce4 + url: "https://pub.dev" + source: hosted + version: "6.0.0" flutter_launcher_icons: dependency: "direct main" description: diff --git a/mih_ui/pubspec.yaml b/mih_ui/pubspec.yaml index cd20d55a..88e94c22 100644 --- a/mih_ui/pubspec.yaml +++ b/mih_ui/pubspec.yaml @@ -12,6 +12,7 @@ dependencies: sdk: flutter flutter_web_plugins: sdk: flutter + flutter_dotenv: ^6.0.0 cupertino_icons: ^1.0.8 font_awesome_flutter: ^10.7.0 @@ -76,6 +77,7 @@ dev_dependencies: flutter: uses-material-design: true assets: + - .env - lib/mih_package_components/assets/images/ - lib/mih_package_components/assets/fonts/ - lib/mih_package_components/assets/images/loyalty_cards/ From 726a60ad2517b8c12d99fd1d24eeb0d39b7a772c Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 4 Feb 2026 15:54:07 +0200 Subject: [PATCH 05/31] BUG: Fix exposed ports on mih server --- .DS_Store | Bin 10244 -> 10244 bytes docker-compose.yml | 24 ++++++++++++------------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.DS_Store b/.DS_Store index 03fe24efd63baf02bcbb1f3f70c3f49648b43260..1cf57d2e96e3e92735b8433848419124a13dfdb7 100644 GIT binary patch delta 33 pcmZn(XbG6$&nUSuU^hRbcb-ZgcS3bPVJ!B)8<|rw~w4 Xkb!K2fB~8nn-wJj*fz5({AC9KmPtvj diff --git a/docker-compose.yml b/docker-compose.yml index a7c0de6f..3f209328 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,7 +12,7 @@ services: ports: - '80:80' # Public HTTP - '443:443' # Public HTTPS - - '81:81' # Admin Web Port + - '127.0.0.1:81:81' # Admin Web Port volumes: - ./mih_nginx/data:/data - ./mih_nginx/letsencrypt:/etc/letsencrypt @@ -38,8 +38,8 @@ services: - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: - - "3000:3000" - - "222:22" + - "127.0.0.1:3000:3000" + - "127.0.0.1:222:22" depends_on: mih-gitea-db: condition: service_healthy @@ -68,7 +68,7 @@ services: depends_on: - mih-db ports: - - 3567:3567 + - '127.0.0.1:3567:3567' environment: REFRESH_TOKEN_VALIDITY: '604800' ACCESS_TOKEN_VALIDITY: '86400' @@ -94,7 +94,7 @@ services: image: wordpress restart: always ports: - - 8081:80 + - '127.0.0.1:8081:80' environment: WORDPRESS_DB_HOST: mih-wp-db WORDPRESS_DB_USER: ${WP_SQL_USER} @@ -123,7 +123,7 @@ services: build: context: ./mih_ui ports: - - "83:83" + - "127.0.0.1:83:83" networks: - mih-network depends_on: @@ -135,7 +135,7 @@ services: target: builder container_name: mih-api-hub ports: - - 8080:80 + - "127.0.0.1:8080:80" volumes: - ./mih_api_hub:/app networks: @@ -156,7 +156,7 @@ services: networks: - mih-network ports: - - '3306:3306' + - '127.0.0.1:3306:3306' volumes: - ./mih_db:/var/lib/mysql #============== PHP My Admin ==================================================================== @@ -182,8 +182,8 @@ services: hostname: mih-minio image: minio/minio ports: - - '9000:9000' - - '9001:9001' + - '127.0.0.1:9000:9000' + - '127.0.0.1:9001:9001' volumes: - './mih_minio:/data' environment: @@ -197,7 +197,7 @@ services: container_name: mih-monitor image: portainer/portainer-ce:2.20.3 ports: - - 9444:9443 + - '127.0.0.1:9444:9443' volumes: - ./mih_monitor/data:/data - /var/run/docker.sock:/var/run/docker.sock @@ -209,7 +209,7 @@ services: container_name: mih-ai image: ollama/ollama:latest ports: - - 11434:11434 + - '127.0.0.1:11434:11434' volumes: - ./mih_ai/ollama/ollama:/root/.ollama pull_policy: always From 071612a5217f1b6ce57041335662035da10976eb Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 4 Feb 2026 15:59:11 +0200 Subject: [PATCH 06/31] BUG: API Wildcard CROS issue --- mih_api_hub/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mih_api_hub/main.py b/mih_api_hub/main.py index c83e79bc..34329f3f 100644 --- a/mih_api_hub/main.py +++ b/mih_api_hub/main.py @@ -46,7 +46,7 @@ origins = [ "http://MIH-API-Hub:80", "http://MIH-API-Hub", "http://api.mzansi-innovation-hub.co.za", - "*", + "http://app.mzansi-innovation-hub.co.za", ] init( From eb9371402236381a0128763e17debc94b6d217cf Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 16 Feb 2026 13:06:22 +0200 Subject: [PATCH 07/31] add ds_store file to ingore file --- .gitignore | 3 ++- mih_api_hub/.gitignore | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index d6c36b79..548552a8 100644 --- a/.gitignore +++ b/.gitignore @@ -10,4 +10,5 @@ Mzansi_Mail/ .venv google-chrome-stable_current_amd64.deb .env -Frontend/android/app/.cxx/ \ No newline at end of file +Frontend/android/app/.cxx/ +.DS_Store \ No newline at end of file diff --git a/mih_api_hub/.gitignore b/mih_api_hub/.gitignore index 156d46ab..fb1147e5 100644 --- a/mih_api_hub/.gitignore +++ b/mih_api_hub/.gitignore @@ -1,3 +1,4 @@ .env __pycache__/ -temp*.pdf \ No newline at end of file +temp*.pdf +.DS_Store \ No newline at end of file From a29d0afeb8f29867eb485bb8f82f0db4409996a3 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 16 Feb 2026 13:25:46 +0200 Subject: [PATCH 08/31] update version number of mih --- mih_ui/lib/mih_config/mih_theme.dart | 2 +- mih_ui/pubspec.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mih_ui/lib/mih_config/mih_theme.dart b/mih_ui/lib/mih_config/mih_theme.dart index dd7ea4c1..02f1fa42 100644 --- a/mih_ui/lib/mih_config/mih_theme.dart +++ b/mih_ui/lib/mih_config/mih_theme.dart @@ -9,7 +9,7 @@ class MihTheme { late String loadingAssetText; late TargetPlatform platform; bool kIsWeb = const bool.fromEnvironment('dart.library.js_util'); - String latestVersion = "1.2.5"; + String latestVersion = "1.2.6"; MihTheme() { mode = "Dark"; } diff --git a/mih_ui/pubspec.yaml b/mih_ui/pubspec.yaml index 88e94c22..6d2db76a 100644 --- a/mih_ui/pubspec.yaml +++ b/mih_ui/pubspec.yaml @@ -1,7 +1,7 @@ name: mzansi_innovation_hub description: "" publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 1.2.5+126 +version: 1.2.6+127 # version: 1.1.1+97 #--- Updated version for upgrader package testing environment: From 141611b84d3031ca1fc43e27ceb1d93870cb0c45 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 16 Feb 2026 13:43:15 +0200 Subject: [PATCH 09/31] fix mzansi ai modal --- mih_ui/lib/mih_providers/mzansi_ai_provider.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mih_ui/lib/mih_providers/mzansi_ai_provider.dart b/mih_ui/lib/mih_providers/mzansi_ai_provider.dart index be9c7f2b..19d00ae7 100644 --- a/mih_ui/lib/mih_providers/mzansi_ai_provider.dart +++ b/mih_ui/lib/mih_providers/mzansi_ai_provider.dart @@ -20,7 +20,7 @@ class MzansiAiProvider extends ChangeNotifier { ollamaProvider = OllamaProvider( baseUrl: "${AppEnviroment.baseAiUrl}/api", model: AppEnviroment.getEnv() == "Prod" - ? 'qwen3-vl:8b' + ? 'qwen3-vl:8b-instruct' : "qwen3-vl:2b-instruct", think: false, systemPrompt: "---INSTRUCTION START---\n" From 4b47bf5288657063c6e92b1d9e52e2243e35c8f6 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 16 Feb 2026 14:08:00 +0200 Subject: [PATCH 10/31] enhacne install/ update mih button to cater for huawei --- .../about_mih/package_tools/mih_info.dart | 116 +++++++++++++++++- 1 file changed, 115 insertions(+), 1 deletion(-) diff --git a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart index f60e3f7b..b8fd02ae 100644 --- a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart +++ b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart @@ -1,7 +1,9 @@ import 'package:flutter_speed_dial/flutter_speed_dial.dart'; +import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_objects/profile_link.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_package_components/mih_package_window.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_profile_links.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_business_details_services.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_install_services.dart'; @@ -432,7 +434,119 @@ class _MihInfoState extends State { children: [ MihButton( onPressed: () { - MihInstallServices().installMihTrigger(context); + if (MzansiInnovationHub.of(context)!.theme.getPlatform() == + "Android") { + showDialog( + context: context, + builder: (context) { + return MihPackageWindow( + fullscreen: false, + windowTitle: "Select Option", + onWindowTapClose: () { + context.pop(); + }, + windowBody: Column( + children: [ + Text( + "Please select the platform you want to install/ Update MIH from", + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 25), + MihButton( + onPressed: () { + launchSocialUrl( + Uri.parse( + "https://play.google.com/store/apps/details?id=za.co.mzansiinnovationhub.mih", + ), + ); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FaIcon( + FontAwesomeIcons.googlePlay, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + const SizedBox(width: 10), + Text( + "Play Store", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + const SizedBox( + height: 10, + ), + MihButton( + onPressed: () { + launchSocialUrl( + Uri.parse( + "https://appgallery.huawei.com/app/C113315335?pkgName=za.co.mzansiinnovationhub.mih", + ), + ); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + FaIcon( + Icons.store, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + const SizedBox(width: 10), + Text( + "App Gallery", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ), + ], + ), + ); + }, + ); + } else { + MihInstallServices().installMihTrigger(context); + } }, buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), From 8a384921c5f15b042cbf28fefec0512a7cb524db Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 16 Feb 2026 14:41:51 +0200 Subject: [PATCH 11/31] fix web cros issues with fixed dev port --- .vscode/launch.json | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.vscode/launch.json b/.vscode/launch.json index e21f3f8c..4a7c8618 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,6 +11,17 @@ "type": "dart", "program": "lib/main_dev.dart" }, + { + "name": "Debug (web)", + "cwd": "mih_ui", + "request": "launch", + "type": "dart", + "program": "lib/main_dev.dart", + "args": [ + "--web-port", + "1995" + ] + }, { "name": "Profile", "cwd": "mih_ui", From fdb28080e39f7f2c65dc77a34862df72fc6758d1 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 16 Feb 2026 14:42:33 +0200 Subject: [PATCH 12/31] fix web cros issues with fixed dev port pt2 --- mih_api_hub/main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mih_api_hub/main.py b/mih_api_hub/main.py index 34329f3f..3d1151f1 100644 --- a/mih_api_hub/main.py +++ b/mih_api_hub/main.py @@ -42,6 +42,7 @@ st_api_key = os.getenv("SUPERTOKENS_API_KEY") origins = [ "http://localhost", "http://localhost:80", + "http://localhost:1995", "http://localhost:8080", "http://MIH-API-Hub:80", "http://MIH-API-Hub", From f8a722eb507eda0abb68da95b5d055c6058d119f Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 16 Feb 2026 14:43:34 +0200 Subject: [PATCH 13/31] change design on profile links and add git option --- .../mih_profile_links.dart | 134 +++++++++--------- .../about_mih/package_tools/mih_info.dart | 8 ++ 2 files changed, 74 insertions(+), 68 deletions(-) diff --git a/mih_ui/lib/mih_package_components/mih_profile_links.dart b/mih_ui/lib/mih_package_components/mih_profile_links.dart index 29e7acc0..1708d4db 100644 --- a/mih_ui/lib/mih_package_components/mih_profile_links.dart +++ b/mih_ui/lib/mih_package_components/mih_profile_links.dart @@ -3,7 +3,7 @@ import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_objects/profile_link.dart'; -import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tile.dart'; +import 'package:mzansi_innovation_hub/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -26,72 +26,87 @@ class MihProfileLinks extends StatefulWidget { class _MihProfileLinksState extends State { Widget displayLinkButton(ProfileLink link) { IconData iconData; - Color iconColor; + Color btnColor; + Color iconColor = Colors.white; switch (link.destination.toLowerCase()) { case "youtube": iconData = FontAwesomeIcons.youtube; - iconColor = const Color(0xFFFF0000); + btnColor = const Color(0xFFFF0000); break; case "tiktok": iconData = FontAwesomeIcons.tiktok; - iconColor = const Color(0xFF000000); + btnColor = const Color(0xFF000000); break; case "twitch": iconData = FontAwesomeIcons.twitch; - iconColor = const Color(0xFF6441a5); + btnColor = const Color(0xFF6441a5); break; case "threads": iconData = FontAwesomeIcons.threads; - iconColor = const Color(0xFF000000); + btnColor = const Color(0xFF000000); break; case "whatsapp": iconData = FontAwesomeIcons.whatsapp; - iconColor = const Color(0xFF25D366); + btnColor = const Color(0xFF25D366); break; case "instagram": iconData = FontAwesomeIcons.instagram; - iconColor = const Color(0xFFF56040); + btnColor = const Color(0xFFF56040); break; case "x": iconData = FontAwesomeIcons.xTwitter; - iconColor = const Color(0xFF000000); + btnColor = const Color(0xFF000000); break; case "linkedin": iconData = FontAwesomeIcons.linkedin; - iconColor = const Color(0xFF0a66c2); + btnColor = const Color(0xFF0a66c2); break; case "facebook": iconData = FontAwesomeIcons.facebook; - iconColor = const Color(0xFF4267B2); + btnColor = const Color(0xFF4267B2); break; case "reddit": iconData = FontAwesomeIcons.reddit; - iconColor = const Color(0xFFFF4500); + btnColor = const Color(0xFFFF4500); break; case "discord": iconData = FontAwesomeIcons.discord; - iconColor = const Color(0xFF5865F2); + btnColor = const Color(0xFF5865F2); + break; + case "git": + iconData = FontAwesomeIcons.git; + btnColor = const Color(0xFF73A952); break; default: iconData = FontAwesomeIcons.link; - iconColor = MihColors.getPrimaryColor( + btnColor = MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"); } - - return MihPackageTile( - onTap: () { + return MihButton( + onPressed: () { launchSocialUrl(Uri.parse(link.web_link)); }, - appName: link.destination, - appIcon: Icon( + buttonColor: btnColor, + child: FaIcon( iconData, color: iconColor, + size: 33, ), - iconSize: 200, - textColor: Colors.black, - // MihColors.getPrimaryColor( - // MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ); + // return MihPackageTile( + // onTap: () { + // launchSocialUrl(Uri.parse(link.web_link)); + // }, + // appName: link.destination, + // appIcon: Icon( + // iconData, + // color: btnColor, + // ), + // iconSize: 200, + // textColor: Colors.black, + // // MihColors.getPrimaryColor( + // // MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + // ); } Future launchSocialUrl(Uri linkUrl) async { @@ -112,52 +127,35 @@ class _MihProfileLinksState extends State { ? EdgeInsets.symmetric(horizontal: width * 0.2) : EdgeInsets.symmetric(horizontal: width * 0.075) : EdgeInsetsGeometry.all(0), - child: Material( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark") - .withValues(alpha: 0.6), - borderRadius: BorderRadius.circular(25), - elevation: 10, - shadowColor: Colors.black, - child: Container( - width: 500, - padding: EdgeInsets.all(10), - decoration: BoxDecoration( - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - borderRadius: BorderRadius.circular(10), - ), - child: widget.links.isEmpty - ? SizedBox( - height: 35, - child: Text( - "No Profile Links", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - ) - : Wrap( - alignment: WrapAlignment.center, - runSpacing: 15, - spacing: 15, - children: widget.links.map( - (link) { - return SizedBox( - width: widget.buttonSize ?? 80, - height: widget.buttonSize ?? 80, - child: displayLinkButton(link), - ); - }, - ).toList(), + child: widget.links.isEmpty + ? SizedBox( + height: 35, + child: Text( + "No Profile Links", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), ), - ), - ), + ), + ) + : Wrap( + alignment: WrapAlignment.center, + runSpacing: 15, + spacing: 15, + children: widget.links.map( + (link) { + return SizedBox( + width: widget.buttonSize ?? 80, + height: widget.buttonSize ?? 80, + child: displayLinkButton(link), + ); + }, + ).toList(), + ), ); }, ); diff --git a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart index b8fd02ae..4397b447 100644 --- a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart +++ b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart @@ -850,6 +850,14 @@ class _MihInfoState extends State { destination: "Reddit", web_link: "https://www.reddit.com/r/Mzani_Innovation_Hub/", ), + ProfileLink( + idprofile_links: 1, + app_id: "1234", + business_id: "", + destination: "Git", + web_link: + "https://git.mzansi-innovation-hub.co.za/yaso_meth/mih-project", + ), ]; return Column( children: [ From 103ccdc0228aed74b9e2131c31d399b186e38e66 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 16 Feb 2026 15:23:16 +0200 Subject: [PATCH 14/31] Add scroll bar to mih --- .../package_tools/package_tool_one.dart | 1 + .../package_tools/package_tool_three.dart | 1 + .../package_tools/package_tool_two.dart | 1 + .../package_tools/package_tool_zero.dart | 1 + .../mih_package_window.dart | 5 +- .../package_tools/currency_exchange_rate.dart | 1 + .../calculator/package_tools/simple_calc.dart | 1 + .../calculator/package_tools/tip_calc.dart | 1 + .../package_tools/mih_forgot_password.dart | 145 +++++++------- .../package_tools/mih_register.dart | 1 + .../package_tools/mih_reset_password.dart | 181 +++++++++--------- .../package_tools/mih_sign_in.dart | 1 + .../package_tools/mine_sweeper_game.dart | 1 + .../mine_sweeper_quick_start_guide.dart | 1 + .../package_tools/mih_contacts.dart | 1 + .../package_tools/mih_search_mzansi.dart | 4 + .../mih_review_business_window.dart | 1 + .../mih_update_business_details_window.dart | 1 + .../mih_update_my_business_user_details.dart | 1 + .../package_tools/mih_business_details.dart | 1 + .../mih_business_details_view.dart | 1 + .../package_tools/mih_business_qr_code.dart | 1 + .../package_tools/mih_my_business_user.dart | 1 + .../package_tools/mih_personal_profile.dart | 1 + .../mih_personal_profile_view.dart | 1 + .../package_tools/mih_personal_settings.dart | 1 + .../package_tools/patient_info.dart | 1 + .../lib/mih_services/mih_alert_services.dart | 15 ++ 28 files changed, 205 insertions(+), 168 deletions(-) diff --git a/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_one.dart b/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_one.dart index 3406a341..67404fcf 100644 --- a/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_one.dart +++ b/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_one.dart @@ -161,6 +161,7 @@ class _PackageToolOneState extends State { return Stack( children: [ MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" diff --git a/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_three.dart b/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_three.dart index 1682426a..c91f3299 100644 --- a/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_three.dart +++ b/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_three.dart @@ -111,6 +111,7 @@ class _PackageToolThreeState extends State { return Stack( children: [ MihSingleChildScroll( + scrollbarOn: true, child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ diff --git a/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_two.dart b/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_two.dart index f6713a51..181f34b5 100644 --- a/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_two.dart +++ b/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_two.dart @@ -24,6 +24,7 @@ class _PackageToolTwoState extends State { Widget getBody() { return MihSingleChildScroll( + scrollbarOn: true, child: Column( mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.max, diff --git a/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_zero.dart b/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_zero.dart index 5b9cf66a..7bf24130 100644 --- a/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_zero.dart +++ b/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_zero.dart @@ -25,6 +25,7 @@ class _PackageToolZeroState extends State { Widget getBody() { return MihSingleChildScroll( + scrollbarOn: true, child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ diff --git a/mih_ui/lib/mih_package_components/mih_package_window.dart b/mih_ui/lib/mih_package_components/mih_package_window.dart index e2dc8720..cb9afb40 100644 --- a/mih_ui/lib/mih_package_components/mih_package_window.dart +++ b/mih_ui/lib/mih_package_components/mih_package_window.dart @@ -197,7 +197,10 @@ class _MihPackageWindowState extends State { maxHeight: windowHeight * 0.85, maxWidth: windowWidth * 0.85, ), - child: MihSingleChildScroll(child: widget.windowBody), + child: MihSingleChildScroll( + scrollbarOn: true, + child: widget.windowBody, + ), ), ), ), diff --git a/mih_ui/lib/mih_packages/calculator/package_tools/currency_exchange_rate.dart b/mih_ui/lib/mih_packages/calculator/package_tools/currency_exchange_rate.dart index ba7ea0a5..c9ed4c87 100644 --- a/mih_ui/lib/mih_packages/calculator/package_tools/currency_exchange_rate.dart +++ b/mih_ui/lib/mih_packages/calculator/package_tools/currency_exchange_rate.dart @@ -290,6 +290,7 @@ class _CurrencyExchangeRateState extends State { return Consumer( builder: (context, calculatorProvider, child) { return MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" diff --git a/mih_ui/lib/mih_packages/calculator/package_tools/simple_calc.dart b/mih_ui/lib/mih_packages/calculator/package_tools/simple_calc.dart index 4a5e05fd..1d2c148d 100644 --- a/mih_ui/lib/mih_packages/calculator/package_tools/simple_calc.dart +++ b/mih_ui/lib/mih_packages/calculator/package_tools/simple_calc.dart @@ -94,6 +94,7 @@ class _SimpleCalcState extends State { } } return MihSingleChildScroll( + scrollbarOn: true, child: Column( mainAxisAlignment: MainAxisAlignment.start, mainAxisSize: MainAxisSize.min, diff --git a/mih_ui/lib/mih_packages/calculator/package_tools/tip_calc.dart b/mih_ui/lib/mih_packages/calculator/package_tools/tip_calc.dart index 3553a4c0..a8d9a572 100644 --- a/mih_ui/lib/mih_packages/calculator/package_tools/tip_calc.dart +++ b/mih_ui/lib/mih_packages/calculator/package_tools/tip_calc.dart @@ -259,6 +259,7 @@ class _TipCalcState extends State { Widget getBody(double width) { return MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" ? EdgeInsets.symmetric(horizontal: width * 0.2) diff --git a/mih_ui/lib/mih_packages/mih_authentication/package_tools/mih_forgot_password.dart b/mih_ui/lib/mih_packages/mih_authentication/package_tools/mih_forgot_password.dart index a19f11f5..b4406da8 100644 --- a/mih_ui/lib/mih_packages/mih_authentication/package_tools/mih_forgot_password.dart +++ b/mih_ui/lib/mih_packages/mih_authentication/package_tools/mih_forgot_password.dart @@ -5,6 +5,7 @@ import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tool_body.dart'; +import 'package:mzansi_innovation_hub/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; @@ -139,89 +140,85 @@ class _MihForgotPasswordState extends State { validateInput(); } }, - child: SafeArea( - child: SingleChildScrollView( - physics: const BouncingScrollPhysics(), - child: Padding( - padding: MzansiInnovationHub.of(context)!.theme.screenType == - "desktop" - ? EdgeInsets.symmetric(vertical: 25, horizontal: width * 0.2) - : EdgeInsets.symmetric(vertical: 25, horizontal: width * 0.075), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - //logo - Icon( - Icons.lock, - size: 100, + child: MihSingleChildScroll( + scrollbarOn: true, + child: Padding( + padding: MzansiInnovationHub.of(context)!.theme.screenType == + "desktop" + ? EdgeInsets.symmetric(vertical: 25, horizontal: width * 0.2) + : EdgeInsets.symmetric(vertical: 25, horizontal: width * 0.075), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.max, + children: [ + //logo + Icon( + Icons.lock, + size: 100, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + //spacer + const SizedBox(height: 10), + //Heading + Text( + 'Forgot Password', + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), - //spacer - const SizedBox(height: 10), - //Heading - Text( - 'Forgot Password', - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( + ), + const SizedBox(height: 25), + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + controller: emailController, + multiLineInput: false, + requiredText: true, + hintText: "Email", + validator: (value) { + return MihValidationServices().validateEmail(value); + }, ), - ), - const SizedBox(height: 25), - MihForm( - formKey: _formKey, - formFields: [ - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: emailController, - multiLineInput: false, - requiredText: true, - hintText: "Email", - validator: (value) { - return MihValidationServices().validateEmail(value); + //spacer + const SizedBox(height: 20), + Align( + alignment: Alignment.center, + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + prePassResteWarning(); + } else { + MihAlertServices().inputErrorAlert(context); + } }, - ), - //spacer - const SizedBox(height: 20), - Align( - alignment: Alignment.center, - child: MihButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - prePassResteWarning(); - } else { - MihAlertServices().inputErrorAlert(context); - } - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - width: 300, - child: Text( - "Reset Password", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Reset Password", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, ), ), ), - ], - ), - ], - ), + ), + ], + ), + ], ), ), ), diff --git a/mih_ui/lib/mih_packages/mih_authentication/package_tools/mih_register.dart b/mih_ui/lib/mih_packages/mih_authentication/package_tools/mih_register.dart index 0622cedb..f6555b88 100644 --- a/mih_ui/lib/mih_packages/mih_authentication/package_tools/mih_register.dart +++ b/mih_ui/lib/mih_packages/mih_authentication/package_tools/mih_register.dart @@ -205,6 +205,7 @@ class _MihRegisterState extends State { } }, child: MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" diff --git a/mih_ui/lib/mih_packages/mih_authentication/package_tools/mih_reset_password.dart b/mih_ui/lib/mih_packages/mih_authentication/package_tools/mih_reset_password.dart index eb776b02..72fe56e2 100644 --- a/mih_ui/lib/mih_packages/mih_authentication/package_tools/mih_reset_password.dart +++ b/mih_ui/lib/mih_packages/mih_authentication/package_tools/mih_reset_password.dart @@ -5,6 +5,7 @@ import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tool_body.dart'; +import 'package:mzansi_innovation_hub/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_text_form_field.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; @@ -104,110 +105,104 @@ class _MihResetPasswordState extends State { } } }, - child: SafeArea( - child: SingleChildScrollView( - physics: const BouncingScrollPhysics(), - child: Padding( - padding: - MzansiInnovationHub.of(context)!.theme.screenType == "desktop" - ? EdgeInsets.symmetric(horizontal: width * 0.2) - : EdgeInsets.symmetric(horizontal: width * 0.075), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - // Text("Token: ${widget.token}"), // For testing purposes only - //logo - Icon( - Icons.lock, - size: 100, + child: MihSingleChildScroll( + scrollbarOn: true, + child: Padding( + padding: + MzansiInnovationHub.of(context)!.theme.screenType == "desktop" + ? EdgeInsets.symmetric(horizontal: width * 0.2) + : EdgeInsets.symmetric(horizontal: width * 0.075), + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + // Text("Token: ${widget.token}"), // For testing purposes only + //logo + Icon( + Icons.lock, + size: 100, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + //spacer + const SizedBox(height: 10), + //Heading + Text( + 'Reset Password', + style: TextStyle( + fontSize: 25, + fontWeight: FontWeight.bold, color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), ), - //spacer - const SizedBox(height: 10), - //Heading - Text( - 'Reset Password', - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( + ), + //spacer + const SizedBox(height: 25), + MihForm( + formKey: _formKey, + formFields: [ + MihTextFormField( + fillColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + controller: passwordController, + multiLineInput: false, + requiredText: true, + hintText: "Password", + passwordMode: true, + autofillHints: const [AutofillHints.password], + validator: (value) { + return MihValidationServices().validatePassword(value); + }, ), - ), - //spacer - const SizedBox(height: 25), - MihForm( - formKey: _formKey, - formFields: [ - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: passwordController, - multiLineInput: false, - requiredText: true, - hintText: "Password", - passwordMode: true, - autofillHints: const [AutofillHints.password], - validator: (value) { - return MihValidationServices().validatePassword(value); + //spacer + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + controller: confirmPasswordController, + multiLineInput: false, + requiredText: true, + hintText: "Confirm Password", + passwordMode: true, + autofillHints: const [AutofillHints.password], + validator: (value) { + return MihValidationServices().validatePassword(value); + }, + ), + //spacer + const SizedBox(height: 25), + // sign in button + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitFormInput(); + } else { + MihAlertServices().inputErrorAlert(context); + } }, - ), - //spacer - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( + buttonColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: confirmPasswordController, - multiLineInput: false, - requiredText: true, - hintText: "Confirm Password", - passwordMode: true, - autofillHints: const [AutofillHints.password], - validator: (value) { - return MihValidationServices().validatePassword(value); - }, - ), - //spacer - const SizedBox(height: 25), - // sign in button - Center( - child: MihButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - submitFormInput(); - } else { - MihAlertServices().inputErrorAlert(context); - } - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - width: 300, - child: Text( - "Reset Password", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), + width: 300, + child: Text( + "Reset Password", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, ), ), ), - ], - ), - ], - ), + ), + ], + ), + ], ), ), ), diff --git a/mih_ui/lib/mih_packages/mih_authentication/package_tools/mih_sign_in.dart b/mih_ui/lib/mih_packages/mih_authentication/package_tools/mih_sign_in.dart index 69c327f0..1e64837d 100644 --- a/mih_ui/lib/mih_packages/mih_authentication/package_tools/mih_sign_in.dart +++ b/mih_ui/lib/mih_packages/mih_authentication/package_tools/mih_sign_in.dart @@ -202,6 +202,7 @@ class _MihSignInState extends State { } }, child: MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" diff --git a/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart b/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart index adc07fda..2fcdd04e 100644 --- a/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart +++ b/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart @@ -626,6 +626,7 @@ class _MineSweeperGameState extends State { alignment: Alignment.topCenter, children: [ MihSingleChildScroll( + scrollbarOn: true, child: board.isEmpty && squaresLeft < 0 // Start Up Message before setting up game ? Padding( diff --git a/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_quick_start_guide.dart b/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_quick_start_guide.dart index 939b7055..5dcd790b 100644 --- a/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_quick_start_guide.dart +++ b/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_quick_start_guide.dart @@ -845,6 +845,7 @@ class _MineSweeperQuickStartGuideState Widget getBody(double width) { return MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: EdgeInsets.symmetric(horizontal: width / 20), child: Column( diff --git a/mih_ui/lib/mih_packages/mzansi_directory/package_tools/mih_contacts.dart b/mih_ui/lib/mih_packages/mzansi_directory/package_tools/mih_contacts.dart index cc7c8f98..4814d109 100644 --- a/mih_ui/lib/mih_packages/mzansi_directory/package_tools/mih_contacts.dart +++ b/mih_ui/lib/mih_packages/mzansi_directory/package_tools/mih_contacts.dart @@ -28,6 +28,7 @@ class _MihContactsState extends State { Widget getBody(double width) { return MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Padding( diff --git a/mih_ui/lib/mih_packages/mzansi_directory/package_tools/mih_search_mzansi.dart b/mih_ui/lib/mih_packages/mzansi_directory/package_tools/mih_search_mzansi.dart index fa2fc911..2fa17e2b 100644 --- a/mih_ui/lib/mih_packages/mzansi_directory/package_tools/mih_search_mzansi.dart +++ b/mih_ui/lib/mih_packages/mzansi_directory/package_tools/mih_search_mzansi.dart @@ -330,6 +330,7 @@ class _MihSearchMzansiState extends State { } else if (directoryProvider.searchedBusinesses.isEmpty && directoryProvider.searchTerm.isNotEmpty) { return MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ const SizedBox(height: 50), @@ -357,6 +358,7 @@ class _MihSearchMzansiState extends State { } else if (directoryProvider.searchedBusinesses.isEmpty && directoryProvider.searchTerm.isEmpty) { return MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 10.0), child: Column( @@ -472,6 +474,7 @@ class _MihSearchMzansiState extends State { } else if (directoryProvider.searchedUsers.isEmpty && directoryProvider.searchTerm.isEmpty) { return MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 10.0), child: Column( @@ -533,6 +536,7 @@ class _MihSearchMzansiState extends State { } else if (directoryProvider.searchedUsers.isEmpty && directoryProvider.searchTerm.isNotEmpty) { return MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ const SizedBox(height: 50), diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_review_business_window.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_review_business_window.dart index 539c4f52..4b1d22cd 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_review_business_window.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_review_business_window.dart @@ -316,6 +316,7 @@ class _MihReviewBusinessWindowState extends State { ] : null, windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart index 67b1c937..46e7dc0c 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart @@ -251,6 +251,7 @@ class _MihUpdateBusinessDetailsWindowState context.pop(); }, windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_my_business_user_details.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_my_business_user_details.dart index 89082b31..e716f07a 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_my_business_user_details.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_my_business_user_details.dart @@ -127,6 +127,7 @@ class _MihUpdateMyBusinessUserDetailsState builder: (BuildContext context, MzansiProfileProvider mzansiProfileProvider, Widget? child) { return MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart index 29e12043..e0324a0a 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart @@ -60,6 +60,7 @@ class _MihBusinessDetailsState extends State { return Stack( children: [ MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart index ea6a1edf..8855abe4 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart @@ -58,6 +58,7 @@ class _MihBusinessDetailsViewState extends State { return Stack( children: [ MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart index f1d695f8..1313b177 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart @@ -367,6 +367,7 @@ class _MihBusinessQrCodeState extends State { alignment: Alignment.topCenter, children: [ MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 15.0), child: Padding( diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart index f78114f1..27ceb514 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart @@ -175,6 +175,7 @@ class _MihMyBusinessUserState extends State { return Stack( children: [ MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" diff --git a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart index 2c36bea8..c579c106 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart @@ -146,6 +146,7 @@ class _MihPersonalProfileState extends State { ); } else { return MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" diff --git a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart index d95e9ad0..212df873 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart @@ -54,6 +54,7 @@ class _MihPersonalProfileViewState extends State { builder: (BuildContext context, MzansiDirectoryProvider directoryProvider, Widget? child) { return MihSingleChildScroll( + scrollbarOn: true, child: Padding( padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" diff --git a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_settings.dart b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_settings.dart index a12f410b..aff6f1b3 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_settings.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_settings.dart @@ -81,6 +81,7 @@ class _MihPersonalSettingsState extends State { Widget getBody(MzansiProfileProvider mzansiProfileProvider) { return MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Center( diff --git a/mih_ui/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart b/mih_ui/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart index 1579db92..283b2ac6 100644 --- a/mih_ui/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart +++ b/mih_ui/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart @@ -306,6 +306,7 @@ class _PatientInfoState extends State { return Stack( children: [ MihSingleChildScroll( + scrollbarOn: true, child: Column( mainAxisAlignment: MainAxisAlignment.start, children: [ diff --git a/mih_ui/lib/mih_services/mih_alert_services.dart b/mih_ui/lib/mih_services/mih_alert_services.dart index df8fbefd..fe01c2ce 100644 --- a/mih_ui/lib/mih_services/mih_alert_services.dart +++ b/mih_ui/lib/mih_services/mih_alert_services.dart @@ -32,6 +32,7 @@ class MihAlertServices { backgroundColor: MihColors.getRedColor( MzansiInnovationHub.of(context)!.theme.mode != "Dark"), windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Icon( @@ -109,6 +110,7 @@ class MihAlertServices { backgroundColor: MihColors.getRedColor( MzansiInnovationHub.of(context)!.theme.mode != "Dark"), windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Icon( @@ -186,6 +188,7 @@ class MihAlertServices { backgroundColor: MihColors.getRedColor( MzansiInnovationHub.of(context)!.theme.mode != "Dark"), windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Icon( @@ -298,6 +301,7 @@ class MihAlertServices { backgroundColor: MihColors.getRedColor( MzansiInnovationHub.of(context)!.theme.mode != "Dark"), windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Icon( @@ -416,6 +420,7 @@ class MihAlertServices { backgroundColor: MihColors.getRedColor( MzansiInnovationHub.of(context)!.theme.mode != "Dark"), windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Icon( @@ -493,6 +498,7 @@ class MihAlertServices { backgroundColor: MihColors.getRedColor( MzansiInnovationHub.of(context)!.theme.mode != "Dark"), windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Icon( @@ -594,6 +600,7 @@ class MihAlertServices { backgroundColor: MihColors.getRedColor( MzansiInnovationHub.of(context)!.theme.mode != "Dark"), windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Icon( @@ -671,6 +678,7 @@ class MihAlertServices { backgroundColor: MihColors.getRedColor( MzansiInnovationHub.of(context)!.theme.mode != "Dark"), windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Icon( @@ -748,6 +756,7 @@ class MihAlertServices { backgroundColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Icon( @@ -830,6 +839,7 @@ class MihAlertServices { backgroundColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Icon( @@ -900,6 +910,7 @@ class MihAlertServices { backgroundColor: MihColors.getRedColor( MzansiInnovationHub.of(context)!.theme.mode != "Dark"), windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Icon( @@ -1007,6 +1018,7 @@ class MihAlertServices { backgroundColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Icon( @@ -1089,6 +1101,7 @@ class MihAlertServices { backgroundColor: MihColors.getGreenColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Icon( @@ -1159,6 +1172,7 @@ class MihAlertServices { backgroundColor: MihColors.getRedColor( MzansiInnovationHub.of(context)!.theme.mode != "Dark"), windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Icon( @@ -1244,6 +1258,7 @@ class MihAlertServices { backgroundColor: MihColors.getRedColor( MzansiInnovationHub.of(context)!.theme.mode != "Dark"), windowBody: MihSingleChildScroll( + scrollbarOn: true, child: Column( children: [ Icon( From d4ba3aaa03757c922ec6b3131cc5cc52bb740152 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 16 Feb 2026 15:34:27 +0200 Subject: [PATCH 15/31] fix short cut icon issue --- mih_ui/android/app/src/main/res/values/arrays.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/mih_ui/android/app/src/main/res/values/arrays.xml b/mih_ui/android/app/src/main/res/values/arrays.xml index fb766383..669016d1 100644 --- a/mih_ui/android/app/src/main/res/values/arrays.xml +++ b/mih_ui/android/app/src/main/res/values/arrays.xml @@ -5,5 +5,6 @@ @drawable/mzansi_wallet_sc @drawable/mzansi_ai_sc @drawable/mih_calculator_sc + @drawable/mzansi_directory_sc \ No newline at end of file From c5267c0540762055c06c7d2c23a391706c4fd803 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Mon, 16 Feb 2026 16:27:39 +0200 Subject: [PATCH 16/31] change follow us link alignments --- mih_ui/lib/mih_package_components/mih_profile_links.dart | 6 +++--- .../lib/mih_packages/about_mih/package_tools/mih_info.dart | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/mih_ui/lib/mih_package_components/mih_profile_links.dart b/mih_ui/lib/mih_package_components/mih_profile_links.dart index 1708d4db..d9457cb3 100644 --- a/mih_ui/lib/mih_package_components/mih_profile_links.dart +++ b/mih_ui/lib/mih_package_components/mih_profile_links.dart @@ -125,7 +125,7 @@ class _MihProfileLinksState extends State { padding: widget.paddingOn == null || widget.paddingOn! ? MzansiInnovationHub.of(context)!.theme.screenType == "desktop" ? EdgeInsets.symmetric(horizontal: width * 0.2) - : EdgeInsets.symmetric(horizontal: width * 0.075) + : EdgeInsets.symmetric(horizontal: width * 0) : EdgeInsetsGeometry.all(0), child: widget.links.isEmpty ? SizedBox( @@ -144,8 +144,8 @@ class _MihProfileLinksState extends State { ) : Wrap( alignment: WrapAlignment.center, - runSpacing: 15, - spacing: 15, + runSpacing: 10, + spacing: 10, children: widget.links.map( (link) { return SizedBox( diff --git a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart index 4397b447..125a3762 100644 --- a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart +++ b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_info.dart @@ -874,7 +874,7 @@ class _MihInfoState extends State { ), MihProfileLinks(links: links), const SizedBox( - height: 25, + height: 75, ), ], ); From 74341a9cc611c5142952f540cfdff7a9fe583e07 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 18 Feb 2026 10:18:03 +0200 Subject: [PATCH 17/31] Enhance Mzansi Profile Look & Feel and workflow --- .../mih_business_info_card_v2.dart | 679 +++++++++++++++++ .../mih_update_business_details_window.dart | 697 ++++++++++-------- .../package_tools/mih_business_details.dart | 154 ++-- .../mih_business_details_set_up.dart | 2 +- .../mih_business_details_view.dart | 68 +- .../mih_edit_personal_profile_window.dart | 399 +++++----- 6 files changed, 1378 insertions(+), 621 deletions(-) create mode 100644 mih_ui/lib/mih_package_components/mih_business_info_card_v2.dart diff --git a/mih_ui/lib/mih_package_components/mih_business_info_card_v2.dart b/mih_ui/lib/mih_package_components/mih_business_info_card_v2.dart new file mode 100644 index 00000000..4df15619 --- /dev/null +++ b/mih_ui/lib/mih_package_components/mih_business_info_card_v2.dart @@ -0,0 +1,679 @@ +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_objects/bookmarked_business.dart'; +import 'package:mzansi_innovation_hub/mih_objects/business.dart'; +import 'package:mzansi_innovation_hub/mih_objects/business_review.dart'; +import 'package:mzansi_innovation_hub/mih_package_components/mih_button.dart'; +import 'package:mzansi_innovation_hub/mih_package_components/mih_icons.dart'; +import 'package:mzansi_innovation_hub/mih_package_components/mih_package_window.dart'; +import 'package:mzansi_innovation_hub/mih_providers/mzansi_directory_provider.dart'; +import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/components/mih_add_bookmark_alert.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/components/mih_delete_bookmark_alert.dart'; +import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/components/mih_review_business_window.dart'; +import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_business_details_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; +import 'package:mzansi_innovation_hub/mih_services/mih_mzansi_directory_services.dart'; +import 'package:provider/provider.dart'; +import 'package:redacted/redacted.dart'; +import 'package:supertokens_flutter/supertokens.dart'; +import 'package:url_launcher/url_launcher.dart'; + +class MihBusinessCardV2 extends StatefulWidget { + final Business business; + final double width; + const MihBusinessCardV2({ + super.key, + required this.business, + required this.width, + }); + + @override + State createState() => _MihBusinessCardV2State(); +} + +class _MihBusinessCardV2State extends State { + Future? _businessReviewFuture; + Future? _bookmarkedBusinessFuture; + bool _isUserSignedIn = false; + + Future _checkUserSession() async { + final doesSessionExist = await SuperTokens.doesSessionExist(); + setState(() { + _isUserSignedIn = doesSessionExist; + }); + } + + RedactedConfiguration getRedactedConfiguration() { + return RedactedConfiguration( + // redactedColor: Colors.pink, + redactedColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ); + } + + Future _makePhoneCall(String phoneNumber) async { + String formattedNumber = phoneNumber.replaceAll("-", ""); + final Uri url = Uri(scheme: 'tel', path: formattedNumber); + if (await canLaunchUrl(url)) { + await launchUrl(url); + } else { + MihAlertServices().errorBasicAlert( + "Error Making Call", + "We couldn't open your phone app to call $formattedNumber. To fix this, make sure you have a phone application installed and it's set as your default dialer.", + context, + ); + } + } + + String? _encodeQueryParameters(Map params) { + return params.entries + .map((MapEntry e) => + '${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}') + .join('&'); + } + + Future _launchEmail( + String recipient, String subject, String body) async { + final Uri emailLaunchUri = Uri( + scheme: 'mailto', + path: recipient, + query: _encodeQueryParameters({ + 'subject': subject, + 'body': body, + }), + ); + + if (await canLaunchUrl(emailLaunchUri)) { + await launchUrl(emailLaunchUri); + } else { + MihAlertServices().errorBasicAlert( + "Error Creating Email", + "We couldn't launch your email app to send a message to $recipient. To fix this, please confirm that you have an email application installed and that it's set as your default.", + context, + ); + } + } + + Future _launchGoogleMapsWithUrl({ + required double latitude, + required double longitude, + String? label, + }) async { + final Uri googleMapsUrl = Uri.parse( + 'https://www.google.com/maps/search/?api=1&query=$latitude,$longitude${label != null ? '&query_place_id=' : ''}', + ); + try { + if (await canLaunchUrl(googleMapsUrl)) { + await launchUrl(googleMapsUrl); + } else { + MihAlertServices().errorBasicAlert( + "Error Opening Maps", + "There was an issue opening maps for ${widget.business.Name}. This usually happens if you don't have a maps app installed or it's not set as your default. Please install one to proceed.", + context, + ); + } + } catch (e) { + MihAlertServices().errorBasicAlert( + "Error Opening Maps", + "There was an issue opening maps for ${widget.business.Name}. This usually happens if you don't have a maps app installed or it's not set as your default. Please install one to proceed.", + context, + ); + } + } + + Future _launchWebsite(String urlString) async { + String newUrl = urlString; + if (!newUrl.startsWith("https://")) { + newUrl = "https://$urlString"; + } + final Uri url = Uri.parse(newUrl); + try { + if (await canLaunchUrl(url)) { + await launchUrl(url); + } else { + MihAlertServices().errorBasicAlert( + "Error Opening Website", + "We couldn't open the link to $newUrl. To view this website, please ensure you have a web browser installed and set as your default.", + context, + ); + } + } catch (e) { + MihAlertServices().errorBasicAlert( + "Error Opening Website", + "We couldn't open the link to $newUrl. To view this website, please ensure you have a web browser installed and set as your default.", + context, + ); + } + } + + Future getUserReview() async { + String user_id = await SuperTokens.getUserId(); + return await MihMzansiDirectoryServices().getUserReviewOfBusiness( + user_id, + widget.business.business_id, + ); + } + + Future getUserBookmark() async { + String user_id = await SuperTokens.getUserId(); + return await MihMzansiDirectoryServices().getUserBookmarkOfBusiness( + user_id, + widget.business.business_id, + ); + } + + bool isValidGps(String coordinateString) { + final RegExp gpsRegex = RegExp( + r"^-?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*-?(1[0-7]\d(\.\d+)?|180(\.0+)?|\d{1,2}(\.\d+)?)$"); + return gpsRegex.hasMatch(coordinateString); + } + + @override + void initState() { + super.initState(); + _checkUserSession(); + _businessReviewFuture = getUserReview(); + _bookmarkedBusinessFuture = getUserBookmark(); + } + + @override + Widget build(BuildContext context) { + // double screenWidth = MediaQuery.of(context).size.width; + return Consumer2( + builder: (BuildContext context, MzansiProfileProvider profileProvider, + MzansiDirectoryProvider directoryProvider, Widget? child) { + double iconSize = 33.0; + return Wrap( + alignment: WrapAlignment.center, + runSpacing: 10, + spacing: 10, + children: [ + Column( + children: [ + SizedBox( + width: 80, + height: 80, + child: MihButton( + onPressed: () { + _makePhoneCall(widget.business.contact_no); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + child: Icon( + Icons.phone, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + size: iconSize, + ), + ), + ), + const SizedBox(height: 2), + FittedBox( + child: Text( + "Call", + style: TextStyle( + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + ), + ), + ), + ], + ), + Column( + children: [ + SizedBox( + width: 80, + height: 80, + child: MihButton( + onPressed: () { + _launchEmail( + widget.business.bus_email, + "Inquiery about ${widget.business.Name}", + "Dear ${widget.business.Name},\n\nI would like to inquire about your services.\n\nBest regards,\n", + ); + }, + buttonColor: MihColors.getPinkColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + child: Icon( + Icons.email, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + size: iconSize, + ), + ), + ), + const SizedBox(height: 2), + FittedBox( + child: Text( + "Email", + style: TextStyle( + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + ), + ), + ), + ], + ), + if (isValidGps(widget.business.gps_location)) + Column( + children: [ + SizedBox( + width: 80, + height: 80, + child: MihButton( + onPressed: () { + final latitude = double.parse( + widget.business.gps_location.split(',')[0]); + final longitude = double.parse( + widget.business.gps_location.split(',')[1]); + _launchGoogleMapsWithUrl( + latitude: latitude, + longitude: longitude, + ); + }, + buttonColor: MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + child: Icon( + Icons.location_on, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + size: iconSize, + ), + ), + ), + const SizedBox(height: 2), + FittedBox( + child: Text( + "Maps", + style: TextStyle( + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + ), + ), + ), + ], + ), + if (widget.business.website.isNotEmpty && + widget.business.website != "") + Column( + children: [ + SizedBox( + width: 80, + height: 80, + child: MihButton( + onPressed: () { + _launchWebsite(widget.business.website); + }, + buttonColor: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + child: Icon( + Icons.language, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + size: iconSize, + ), + ), + ), + const SizedBox(height: 2), + FittedBox( + child: Text( + "Website", + style: TextStyle( + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + ), + ), + ), + ], + ), + FutureBuilder( + future: _businessReviewFuture, + builder: (context, asyncSnapshot) { + if (asyncSnapshot.connectionState == ConnectionState.waiting) { + return Column( + children: [ + SizedBox( + width: 80, + height: 80, + child: MihButton( + onPressed: () {}, + buttonColor: MihColors.getGreyColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + child: Icon( + Icons.star_rate_rounded, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + size: iconSize, + ), + ), + ).redacted(context: context, redact: true), + const SizedBox(height: 2), + FittedBox( + child: Text( + "Rate Us", + style: TextStyle( + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + ), + ), + ).redacted(context: context, redact: true), + ], + ); + } else { + BusinessReview? businessReview = asyncSnapshot.data; + String ratingTitle = ""; + if (businessReview == null) { + ratingTitle = "Rate Us"; + } else { + ratingTitle = "Edit"; + } + return Column( + children: [ + SizedBox( + width: 80, + height: 80, + child: MihButton( + onPressed: () { + businessReviewRatingWindow(directoryProvider, + businessReview, true, widget.width); + }, + buttonColor: MihColors.getYellowColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + child: Icon( + Icons.star_rate_rounded, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + size: iconSize, + ), + ), + ), + const SizedBox(height: 2), + FittedBox( + child: Text( + ratingTitle, + style: TextStyle( + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + ), + ), + ), + ], + ); + } + }, + ), + FutureBuilder( + future: _bookmarkedBusinessFuture, + builder: (context, asyncSnapshot) { + if (asyncSnapshot.connectionState == ConnectionState.waiting) { + return Column( + children: [ + SizedBox( + width: 80, + height: 80, + child: MihButton( + onPressed: () {}, + buttonColor: MihColors.getGreyColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + child: Icon( + Icons.bookmark_add_rounded, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + size: iconSize, + ), + ), + ).redacted(context: context, redact: true), + const SizedBox(height: 2), + FittedBox( + child: Text( + "bookmark", + style: TextStyle( + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + ), + ), + ).redacted(context: context, redact: true), + ], + ); + } else { + BookmarkedBusiness? bookmarkBusiness = asyncSnapshot.data; + String bookmarkDisplayTitle = ""; + if (bookmarkBusiness == null) { + bookmarkDisplayTitle = "Bookmark"; + } else { + bookmarkDisplayTitle = "Remove"; + } + return Column( + children: [ + SizedBox( + width: 80, + height: 80, + child: MihButton( + onPressed: () { + if (bookmarkBusiness == null) { + showAddBookmarkAlert(); + } else { + showDeleteBookmarkAlert(bookmarkBusiness); + } + }, + buttonColor: MihColors.getBluishPurpleColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + child: Icon( + bookmarkBusiness == null + ? Icons.bookmark_add_rounded + : Icons.bookmark_remove_rounded, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + size: iconSize, + ), + ), + ), + const SizedBox(height: 2), + FittedBox( + child: Text( + bookmarkDisplayTitle, + style: TextStyle( + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + ), + ), + ), + ], + ); + } + }, + ), + ], + ); + }, + ); + } + + Future businessReviewRatingWindow( + MzansiDirectoryProvider directoryProvider, + BusinessReview? myReview, + bool previouslyRated, + double width) async { + if (_isUserSignedIn) { + showDialog( + barrierDismissible: false, + context: context, + builder: (context) => MihReviewBusinessWindow( + business: widget.business, + businessReview: myReview, + screenWidth: width, + readOnly: false, + onSuccessDismissPressed: () async { + List? businessSearchResults = []; + businessSearchResults = await MihBusinessDetailsServices() + .searchBusinesses(directoryProvider.searchTerm, + directoryProvider.businessTypeFilter, context); + Map> busImagesUrl = {}; + Future businessLogoUrl; + for (var bus in businessSearchResults) { + businessLogoUrl = MihFileApi.getMinioFileUrl(bus.logo_path); + busImagesUrl[bus.business_id] = businessLogoUrl; + } + directoryProvider.setSearchedBusinesses( + searchedBusinesses: businessSearchResults, + businessesImagesUrl: busImagesUrl, + ); + setState(() { + _businessReviewFuture = getUserReview(); + }); + }, + ), + ); + } else { + showSignInRequiredAlert(); + } + } + + void showAddBookmarkAlert() { + if (_isUserSignedIn) { + showDialog( + barrierDismissible: false, + context: context, + builder: (context) => MihAddBookmarkAlert( + business: widget.business, + onSuccessDismissPressed: () async { + _bookmarkedBusinessFuture = getUserBookmark(); + }, + ), + ); + } else { + showSignInRequiredAlert(); + } + } + + void showDeleteBookmarkAlert(BookmarkedBusiness? bookmarkBusiness) { + if (_isUserSignedIn) { + showDialog( + barrierDismissible: false, + context: context, + builder: (context) => MihDeleteBookmarkAlert( + business: widget.business, + bookmarkBusiness: bookmarkBusiness, + onSuccessDismissPressed: () { + _bookmarkedBusinessFuture = getUserBookmark(); + }, + // startUpSearch: widget.startUpSearch, + )); + } else { + showSignInRequiredAlert(); + } + } + + void showSignInRequiredAlert() { + showDialog( + barrierDismissible: false, + context: context, + builder: (context) { + return MihPackageWindow( + fullscreen: false, + windowTitle: null, + onWindowTapClose: () { + context.pop(); + }, + windowBody: Column( + children: [ + Icon( + MihIcons.mihLogo, + size: 125, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + ), + const SizedBox(height: 10), + Text( + "Let's Get Started", + textAlign: TextAlign.center, + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + fontSize: 25, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 15), + Text( + "Ready to dive in to the world of MIH?\nSign in or create a free MIH account to unlock all the powerful features of the MIH app. It's quick and easy!", + style: TextStyle( + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + fontSize: 15, + ), + ), + const SizedBox(height: 25), + Center( + child: MihButton( + onPressed: () { + context.goNamed( + 'mihHome', + extra: true, + ); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + elevation: 10, + width: 300, + child: Text( + "Sign In/ Create Account", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], + ), + ); + }, + ); + } +} diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart index 46e7dc0c..553c31d3 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart @@ -257,273 +257,38 @@ class _MihUpdateBusinessDetailsWindowState MzansiInnovationHub.of(context)!.theme.screenType == "desktop" ? EdgeInsets.symmetric(horizontal: widget.width * 0.05) : EdgeInsets.symmetric(horizontal: widget.width * 0), - child: Column( + child: Stack( children: [ - MihForm( - formKey: _formKey, - formFields: [ - Center( - child: MihCircleAvatar( - imageFile: newSelectedLogoPic != null - ? MemoryImage(newSelectedLogoPic!.bytes!) - : mzansiProfileProvider.businessProfilePicture, - width: 150, - editable: true, - fileNameController: fileNameController, - userSelectedfile: newSelectedLogoPic, - frameColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - backgroundColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - onChange: (selectedfile) { - setState(() { - newSelectedLogoPic = selectedfile; - }); - }, - ), - ), - Visibility( - visible: false, - child: MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: fileNameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Selected File Name", - ), - ), - const SizedBox(height: 20), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: nameController, - multiLineInput: false, - requiredText: true, - hintText: "Business Name", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: typeController, - multiLineInput: false, - requiredText: true, - hintText: "Business Type", - validator: (value) { - return MihValidationServices() - .validateNoSpecialChars(value); - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: emailController, - multiLineInput: false, - requiredText: true, - hintText: "Business Email", - validator: (value) { - return MihValidationServices().validateEmail(value); - }, - ), - const SizedBox(height: 10), - Container( - width: 300, - alignment: Alignment.topLeft, - child: const Text( - "Contact Number:", - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - ), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - CountryCodePicker( - padding: EdgeInsetsGeometry.all(0), - onChanged: (selectedCode) { - setState(() { - countryCodeController.text = - selectedCode.toString(); - }); - debugPrint( - "Selected Country Code: ${countryCodeController.text}"); - }, - initialSelection: countryCodeController.text, - showDropDownButton: false, - pickerStyle: PickerStyle.bottomSheet, - dialogBackgroundColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - barrierColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - Expanded( - child: MihTextFormField( - fillColor: MihColors.getSecondaryColor( + Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + Center( + child: MihCircleAvatar( + imageFile: newSelectedLogoPic != null + ? MemoryImage(newSelectedLogoPic!.bytes!) + : mzansiProfileProvider + .businessProfilePicture, + width: 150, + editable: true, + fileNameController: fileNameController, + userSelectedfile: newSelectedLogoPic, + frameColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - inputColor: MihColors.getPrimaryColor( + backgroundColor: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: contactController, - numberMode: true, - multiLineInput: false, - requiredText: true, - hintText: null, - validator: (value) { - return MihValidationServices().isEmpty(value); + onChange: (selectedfile) { + setState(() { + newSelectedLogoPic = selectedfile; + }); }, ), ), - ], - ), - const SizedBox(height: 10), - MihTextFormField( - height: 250, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: missionVisionController, - multiLineInput: true, - requiredText: true, - hintText: "Business Mission & Vision", - validator: (value) { - return MihValidationServices().validateLength( - missionVisionController.text, 256); - }, - ), - SizedBox( - height: 15, - child: ValueListenableBuilder( - valueListenable: _counter, - builder: - (BuildContext context, int value, Widget? child) { - return Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - "$value", - style: TextStyle( - color: getMissionVisionLimitColor(256), - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(width: 5), - Text( - "/256", - style: TextStyle( - color: getMissionVisionLimitColor(256), - fontWeight: FontWeight.bold, - ), - ), - ], - ); - }, - ), - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: websiteController, - multiLineInput: false, - requiredText: false, - hintText: "Business Website", - validator: (value) { - return MihValidationServices() - .validateWebsite(value, false); - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: regController, - multiLineInput: false, - requiredText: false, - hintText: "Registration No.", - validator: (value) { - // return MihValidationServices().isEmpty(value); - return null; - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: practiceNoController, - multiLineInput: false, - requiredText: false, - hintText: "Practice Number", - validator: (validateValue) { - return null; - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: vatNoController, - multiLineInput: false, - requiredText: false, - hintText: "VAT Number", - validator: (value) { - // return MihValidationServices().isEmpty(value); - return null; - }, - ), - const SizedBox(height: 10), - Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - Flexible( + Visibility( + visible: false, child: MihTextFormField( fillColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == @@ -531,84 +296,374 @@ class _MihUpdateBusinessDetailsWindowState inputColor: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - controller: locationController, + controller: fileNameController, multiLineInput: false, requiredText: true, readOnly: true, - hintText: "GPS Location", + hintText: "Selected File Name", ), ), - const SizedBox(width: 10.0), - MihButton( - onPressed: () { - showDialog( - context: context, - builder: (context) { - return const Mihloadingcircle( - message: "Getting your location", - ); - }, - ); - MIHLocationAPI() - .getGPSPosition(context) - .then((position) { - if (position != null) { - setState(() { - locationController.text = - "${position.latitude}, ${position.longitude}"; - }); - } - //Dismiss loading indicator - context.pop(); - }); - }, - buttonColor: MihColors.getSecondaryColor( + const SizedBox(height: 20), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - width: 100, - child: Text( - "Set", + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: nameController, + multiLineInput: false, + requiredText: true, + hintText: "Business Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: typeController, + multiLineInput: false, + requiredText: true, + hintText: "Business Type", + validator: (value) { + return MihValidationServices() + .validateNoSpecialChars(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: emailController, + multiLineInput: false, + requiredText: true, + hintText: "Business Email", + validator: (value) { + return MihValidationServices() + .validateEmail(value); + }, + ), + const SizedBox(height: 10), + Container( + width: 300, + alignment: Alignment.topLeft, + child: const Text( + "Contact Number:", style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)! - .theme - .mode == - "Dark"), - fontSize: 20, + fontSize: 18, fontWeight: FontWeight.bold, ), ), ), - ], - ), - const SizedBox(height: 25), - Center( - child: MihButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - submitForm(mzansiProfileProvider); - } else { - MihAlertServices().inputErrorAlert(context); - } - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - width: 300, - child: Text( - "Update", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + CountryCodePicker( + padding: EdgeInsetsGeometry.all(0), + onChanged: (selectedCode) { + setState(() { + countryCodeController.text = + selectedCode.toString(); + }); + debugPrint( + "Selected Country Code: ${countryCodeController.text}"); + }, + initialSelection: countryCodeController.text, + showDropDownButton: false, + pickerStyle: PickerStyle.bottomSheet, + dialogBackgroundColor: + MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + barrierColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + Expanded( + child: MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + controller: contactController, + numberMode: true, + multiLineInput: false, + requiredText: true, + hintText: null, + validator: (value) { + return MihValidationServices() + .isEmpty(value); + }, + ), + ), + ], + ), + const SizedBox(height: 10), + MihTextFormField( + height: 250, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: missionVisionController, + multiLineInput: true, + requiredText: true, + hintText: "Business Mission & Vision", + validator: (value) { + return MihValidationServices().validateLength( + missionVisionController.text, 256); + }, + ), + SizedBox( + height: 15, + child: ValueListenableBuilder( + valueListenable: _counter, + builder: (BuildContext context, int value, + Widget? child) { + return Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + "$value", + style: TextStyle( + color: getMissionVisionLimitColor(256), + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(width: 5), + Text( + "/256", + style: TextStyle( + color: getMissionVisionLimitColor(256), + fontWeight: FontWeight.bold, + ), + ), + ], + ); + }, ), ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: websiteController, + multiLineInput: false, + requiredText: false, + hintText: "Business Website", + validator: (value) { + return MihValidationServices() + .validateWebsite(value, false); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: regController, + multiLineInput: false, + requiredText: false, + hintText: "Registration No.", + validator: (value) { + // return MihValidationServices().isEmpty(value); + return null; + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: practiceNoController, + multiLineInput: false, + requiredText: false, + hintText: "Practice Number", + validator: (validateValue) { + return null; + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: vatNoController, + multiLineInput: false, + requiredText: false, + hintText: "VAT Number", + validator: (value) { + // return MihValidationServices().isEmpty(value); + return null; + }, + ), + const SizedBox(height: 10), + Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Flexible( + child: MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + controller: locationController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "GPS Location", + ), + ), + const SizedBox(width: 10.0), + MihButton( + onPressed: () { + showDialog( + context: context, + builder: (context) { + return const Mihloadingcircle( + message: "Getting your location", + ); + }, + ); + MIHLocationAPI() + .getGPSPosition(context) + .then((position) { + if (position != null) { + setState(() { + locationController.text = + "${position.latitude}, ${position.longitude}"; + }); + } + //Dismiss loading indicator + context.pop(); + }); + }, + buttonColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + width: 100, + child: Text( + "Set", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + const SizedBox(height: 25), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitForm(mzansiProfileProvider); + } else { + MihAlertServices().inputErrorAlert(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Update", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + const SizedBox(height: 20), + ], + ), + ], + ), + Positioned( + right: 0, + top: 0, + child: MihButton( + onPressed: () { + //Add validation here + if (_formKey.currentState!.validate()) { + submitForm(mzansiProfileProvider); + } else { + MihAlertServices().inputErrorAlert(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 100, + height: 25, + child: Text( + mzansiProfileProvider.user!.username.isEmpty + ? "Setup Profile" + : "Update", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 15, + fontWeight: FontWeight.bold, ), ), - const SizedBox(height: 20), - ], + ), ), ], ), diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart index e0324a0a..8ac92d58 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart @@ -1,9 +1,10 @@ +import 'package:custom_rating_bar/custom_rating_bar.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_package_components/mih_business_info_card_v2.dart'; import 'package:mzansi_innovation_hub/mih_providers/mzansi_profile_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; -import 'package:mzansi_innovation_hub/mih_package_components/mih_business_info_card.dart'; import 'package:mzansi_innovation_hub/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_button.dart'; @@ -65,28 +66,57 @@ class _MihBusinessDetailsState extends State { padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" ? EdgeInsets.symmetric(horizontal: width * 0.2) - : EdgeInsets.symmetric(horizontal: width * 0.075), + : EdgeInsets.symmetric(horizontal: width * 0), child: Column( children: [ Center( - child: MihCircleAvatar( - key: UniqueKey(), - imageFile: mzansiProfileProvider.businessProfilePicture, - width: 150, - editable: false, - fileNameController: fileNameController, - userSelectedfile: newSelectedLogoPic, - frameColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - backgroundColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - onChange: (selectedfile) { - setState(() { - newSelectedLogoPic = selectedfile; - }); - }, + child: Stack( + children: [ + MihCircleAvatar( + key: UniqueKey(), + imageFile: + mzansiProfileProvider.businessProfilePicture, + width: 150, + editable: false, + fileNameController: fileNameController, + userSelectedfile: newSelectedLogoPic, + frameColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + backgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onChange: (selectedfile) { + setState(() { + newSelectedLogoPic = selectedfile; + }); + }, + ), + Positioned( + bottom: 5, + right: 5, + child: MihButton( + onPressed: () { + // editProfileWindow(width); + editBizProfileWindow( + mzansiProfileProvider, width); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 35, + height: 35, + child: Icon( + Icons.edit, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + ), + ], ), ), FittedBox( @@ -113,6 +143,30 @@ class _MihBusinessDetailsState extends State { ), ), ), + RatingBar.readOnly( + size: 50, + alignment: Alignment.center, + filledIcon: Icons.star, + emptyIcon: Icons.star_border, + halfFilledIcon: Icons.star_half, + filledColor: MihColors.getYellowColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + // MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + emptyColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + halfFilledColor: MihColors.getYellowColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + // MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + isHalfAllowed: true, + initialRating: mzansiProfileProvider + .business!.rating.isNotEmpty + ? double.parse(mzansiProfileProvider.business!.rating) + : 0, + maxRating: 5, + ), const SizedBox(height: 5), Center( child: SizedBox( @@ -134,68 +188,16 @@ class _MihBusinessDetailsState extends State { ), ), const SizedBox(height: 20), - SizedBox( - width: 700, - child: MihBusinessCard( - business: mzansiProfileProvider.business!, - // startUpSearch: null, - width: width, - ), + MihBusinessCardV2( + business: mzansiProfileProvider.business!, + // startUpSearch: null, + width: width, ), const SizedBox(height: 30.0), - Center( - child: MihButton( - onPressed: () { - // Connect with the user - editBizProfileWindow(mzansiProfileProvider, width); - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - width: 300, - child: Text( - "Edit Profile", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ), ], ), ), ), - // Positioned( - // right: 5, - // bottom: 10, - // child: MihFloatingMenu( - // animatedIcon: AnimatedIcons.menu_close, - // children: [ - // SpeedDialChild( - // child: Icon( - // Icons.edit, - // color: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // ), - // label: "Edit Profile", - // labelBackgroundColor: - // MihColors.getGreenColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // labelStyle: TextStyle( - // color: MihColors.getPrimaryColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // fontWeight: FontWeight.bold, - // ), - // backgroundColor: - // MihColors.getGreenColor(MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - // onTap: () { - // editBizProfileWindow(width); - // }, - // ) - // ], - // ), - // ), ], ); }, diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_set_up.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_set_up.dart index a02ef2e7..e7d976e7 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_set_up.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_set_up.dart @@ -765,7 +765,7 @@ class _MihBusinessDetailsSetUpState extends State { "Dark"), width: 300, child: Text( - "Add", + "Set Up Buasiness", style: TextStyle( color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart index 8855abe4..bf03da5d 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart @@ -3,10 +3,10 @@ import 'package:custom_rating_bar/custom_rating_bar.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/main.dart'; +import 'package:mzansi_innovation_hub/mih_package_components/mih_business_info_card_v2.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_providers/mzansi_directory_provider.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; -import 'package:mzansi_innovation_hub/mih_package_components/mih_business_info_card.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_file_services.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_single_child_scroll.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tool_body.dart'; @@ -63,7 +63,7 @@ class _MihBusinessDetailsViewState extends State { padding: MzansiInnovationHub.of(context)!.theme.screenType == "desktop" ? EdgeInsets.symmetric(horizontal: width * 0.2) - : EdgeInsets.symmetric(horizontal: width * 0.075), + : EdgeInsets.symmetric(horizontal: width * 0), child: Column( children: [ FutureBuilder( @@ -155,40 +155,6 @@ class _MihBusinessDetailsViewState extends State { ), ), ), - const SizedBox(height: 5), - // FittedBox( - // child: Text( - // "Mission & Vision", - // style: TextStyle( - // fontSize: 15, - // fontWeight: FontWeight.bold, - // color: MzansiInnovationHub.of(context)! - // .theme - // .secondaryColor(), - // ), - // ), - // ), - Center( - child: SizedBox( - width: 700, - child: Text( - directoryProvider - .selectedBusiness!.mission_vision.isNotEmpty - ? directoryProvider - .selectedBusiness!.mission_vision - : "No Mission & Vision added yet", - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 15, - fontWeight: FontWeight.bold, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - ), - ), - ), - ), - const SizedBox(height: 10), RatingBar.readOnly( size: 50, alignment: Alignment.center, @@ -214,14 +180,32 @@ class _MihBusinessDetailsViewState extends State { : 0, maxRating: 5, ), - const SizedBox(height: 20), - SizedBox( - width: 700, - child: MihBusinessCard( - business: directoryProvider.selectedBusiness!, - width: width, + const SizedBox(height: 5), + Center( + child: SizedBox( + width: 700, + child: Text( + directoryProvider + .selectedBusiness!.mission_vision.isNotEmpty + ? directoryProvider + .selectedBusiness!.mission_vision + : "No Mission & Vision added yet", + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 15, + fontWeight: FontWeight.bold, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), + ), ), ), + const SizedBox(height: 20), + MihBusinessCardV2( + business: directoryProvider.selectedBusiness!, + width: width, + ), ], ), ), diff --git a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart index c0ad5736..7680088c 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart @@ -329,195 +329,232 @@ class _MihEditPersonalProfileWindowState MzansiInnovationHub.of(context)!.theme.screenType == "desktop" ? EdgeInsets.symmetric(horizontal: screenWidth * 0.05) : EdgeInsets.symmetric(horizontal: screenWidth * 0), - child: Column( - mainAxisAlignment: MainAxisAlignment.start, + child: Stack( children: [ - MihForm( - formKey: _formKey, - formFields: [ - Center( - child: MihCircleAvatar( - imageFile: newSelectedProPic != null - ? MemoryImage(newSelectedProPic!.bytes!) - : mzansiProfileProvider.userProfilePicture, - width: 150, - editable: true, - fileNameController: proPicController, - userSelectedfile: newSelectedProPic, - frameColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - backgroundColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - onChange: (selectedImage) { - setState(() { - newSelectedProPic = selectedImage; - }); - }, - ), - ), - // const SizedBox(height: 25.0), - Visibility( - visible: false, - child: MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: proPicController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Selected File Name", - ), - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: usernameController, - multiLineInput: false, - requiredText: true, - hintText: "Username", - validator: (value) { - return MihValidationServices().validateUsername(value); - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: fnameController, - multiLineInput: false, - requiredText: true, - hintText: "First Name", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: lnameController, - multiLineInput: false, - requiredText: true, - hintText: "Last Name", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10.0), - MihTextFormField( - height: 250, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: purposeController, - multiLineInput: true, - requiredText: true, - hintText: "Your Personal Mission", - validator: (value) { - return MihValidationServices() - .validateLength(purposeController.text, 256); - }, - ), - SizedBox( - height: 15, - child: ValueListenableBuilder( - valueListenable: _counter, - builder: - (BuildContext context, int value, Widget? child) { - return Row( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.end, - children: [ - Text( - "$value", - style: TextStyle( - color: getPurposeLimitColor(256), - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(width: 5), - Text( - "/256", - style: TextStyle( - color: getPurposeLimitColor(256), - fontWeight: FontWeight.bold, - ), - ), - ], - ); - }, - ), - ), - const SizedBox(height: 10.0), - MihToggle( - hintText: "Activate Business Account", - initialPostion: businessUser, - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - secondaryFillColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - onChange: (value) { - setState(() { - businessUser = value; - }); - KenLogger.success("Business User: $businessUser"); - }, - ), - const SizedBox(height: 30.0), - Center( - child: MihButton( - onPressed: () { - //Add validation here - if (_formKey.currentState!.validate()) { - submitForm(mzansiProfileProvider); - } else { - MihAlertServices().inputErrorAlert(context); - } - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - width: 300, - child: Text( - mzansiProfileProvider.user!.username.isEmpty - ? "Setup Profile" - : "Update", - style: TextStyle( - color: MihColors.getPrimaryColor( + Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + MihForm( + formKey: _formKey, + formFields: [ + Center( + child: MihCircleAvatar( + imageFile: newSelectedProPic != null + ? MemoryImage(newSelectedProPic!.bytes!) + : mzansiProfileProvider.userProfilePicture, + width: 150, + editable: true, + fileNameController: proPicController, + userSelectedfile: newSelectedProPic, + frameColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, + backgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onChange: (selectedImage) { + setState(() { + newSelectedProPic = selectedImage; + }); + }, ), ), - ), + // const SizedBox(height: 25.0), + Visibility( + visible: false, + child: MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: proPicController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Selected File Name", + ), + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: usernameController, + multiLineInput: false, + requiredText: true, + hintText: "Username", + validator: (value) { + return MihValidationServices() + .validateUsername(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: fnameController, + multiLineInput: false, + requiredText: true, + hintText: "First Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: lnameController, + multiLineInput: false, + requiredText: true, + hintText: "Last Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10.0), + MihTextFormField( + height: 250, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: purposeController, + multiLineInput: true, + requiredText: true, + hintText: "Your Personal Mission", + validator: (value) { + return MihValidationServices() + .validateLength(purposeController.text, 256); + }, + ), + SizedBox( + height: 15, + child: ValueListenableBuilder( + valueListenable: _counter, + builder: (BuildContext context, int value, + Widget? child) { + return Row( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.end, + children: [ + Text( + "$value", + style: TextStyle( + color: getPurposeLimitColor(256), + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(width: 5), + Text( + "/256", + style: TextStyle( + color: getPurposeLimitColor(256), + fontWeight: FontWeight.bold, + ), + ), + ], + ); + }, + ), + ), + const SizedBox(height: 10.0), + MihToggle( + hintText: "Activate Business Account", + initialPostion: businessUser, + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + secondaryFillColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onChange: (value) { + setState(() { + businessUser = value; + }); + KenLogger.success("Business User: $businessUser"); + }, + ), + const SizedBox(height: 30.0), + Center( + child: MihButton( + onPressed: () { + //Add validation here + if (_formKey.currentState!.validate()) { + submitForm(mzansiProfileProvider); + } else { + MihAlertServices().inputErrorAlert(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + mzansiProfileProvider.user!.username.isEmpty + ? "Setup Profile" + : "Update", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ], ), ], ), + Positioned( + right: 0, + top: 0, + child: MihButton( + onPressed: () { + //Add validation here + if (_formKey.currentState!.validate()) { + submitForm(mzansiProfileProvider); + } else { + MihAlertServices().inputErrorAlert(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + width: 100, + height: 25, + child: Text( + mzansiProfileProvider.user!.username.isEmpty + ? "Setup Profile" + : "Update", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 15, + fontWeight: FontWeight.bold, + ), + ), + ), + ), ], ), ), From a7effa3576c9f6ba942bdfad314873c3df505968 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 18 Feb 2026 10:26:41 +0200 Subject: [PATCH 18/31] Update profile link and business card Icons alignment --- .../mih_business_info_card_v2.dart | 218 ++++++++---------- .../mih_profile_links.dart | 12 +- 2 files changed, 103 insertions(+), 127 deletions(-) diff --git a/mih_ui/lib/mih_package_components/mih_business_info_card_v2.dart b/mih_ui/lib/mih_package_components/mih_business_info_card_v2.dart index 4df15619..30ec1fb9 100644 --- a/mih_ui/lib/mih_package_components/mih_business_info_card_v2.dart +++ b/mih_ui/lib/mih_package_components/mih_business_info_card_v2.dart @@ -186,7 +186,7 @@ class _MihBusinessCardV2State extends State { return Consumer2( builder: (BuildContext context, MzansiProfileProvider profileProvider, MzansiDirectoryProvider directoryProvider, Widget? child) { - double iconSize = 33.0; + double iconSize = 50.0; return Wrap( alignment: WrapAlignment.center, runSpacing: 10, @@ -194,22 +194,19 @@ class _MihBusinessCardV2State extends State { children: [ Column( children: [ - SizedBox( + MihButton( width: 80, height: 80, - child: MihButton( - onPressed: () { - _makePhoneCall(widget.business.contact_no); - }, - buttonColor: MihColors.getGreenColor( + onPressed: () { + _makePhoneCall(widget.business.contact_no); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + child: Icon( + Icons.phone, + color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - child: Icon( - Icons.phone, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - size: iconSize, - ), + size: iconSize, ), ), const SizedBox(height: 2), @@ -229,26 +226,23 @@ class _MihBusinessCardV2State extends State { ), Column( children: [ - SizedBox( + MihButton( width: 80, height: 80, - child: MihButton( - onPressed: () { - _launchEmail( - widget.business.bus_email, - "Inquiery about ${widget.business.Name}", - "Dear ${widget.business.Name},\n\nI would like to inquire about your services.\n\nBest regards,\n", - ); - }, - buttonColor: MihColors.getPinkColor( + onPressed: () { + _launchEmail( + widget.business.bus_email, + "Inquiery about ${widget.business.Name}", + "Dear ${widget.business.Name},\n\nI would like to inquire about your services.\n\nBest regards,\n", + ); + }, + buttonColor: MihColors.getPinkColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + child: Icon( + Icons.email, + color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - child: Icon( - Icons.email, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - size: iconSize, - ), + size: iconSize, ), ), const SizedBox(height: 2), @@ -269,30 +263,27 @@ class _MihBusinessCardV2State extends State { if (isValidGps(widget.business.gps_location)) Column( children: [ - SizedBox( + MihButton( width: 80, height: 80, - child: MihButton( - onPressed: () { - final latitude = double.parse( - widget.business.gps_location.split(',')[0]); - final longitude = double.parse( - widget.business.gps_location.split(',')[1]); - _launchGoogleMapsWithUrl( - latitude: latitude, - longitude: longitude, - ); - }, - buttonColor: MihColors.getOrangeColor( + onPressed: () { + final latitude = double.parse( + widget.business.gps_location.split(',')[0]); + final longitude = double.parse( + widget.business.gps_location.split(',')[1]); + _launchGoogleMapsWithUrl( + latitude: latitude, + longitude: longitude, + ); + }, + buttonColor: MihColors.getOrangeColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + child: Icon( + Icons.location_on, + color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - child: Icon( - Icons.location_on, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - size: iconSize, - ), + size: iconSize, ), ), const SizedBox(height: 2), @@ -314,23 +305,20 @@ class _MihBusinessCardV2State extends State { widget.business.website != "") Column( children: [ - SizedBox( + MihButton( width: 80, height: 80, - child: MihButton( - onPressed: () { - _launchWebsite(widget.business.website); - }, - buttonColor: MihColors.getRedColor( + onPressed: () { + _launchWebsite(widget.business.website); + }, + buttonColor: MihColors.getRedColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + child: Icon( + Icons.language, + color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - child: Icon( - Icons.language, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - size: iconSize, - ), + size: iconSize, ), ), const SizedBox(height: 2), @@ -354,21 +342,19 @@ class _MihBusinessCardV2State extends State { if (asyncSnapshot.connectionState == ConnectionState.waiting) { return Column( children: [ - SizedBox( + MihButton( width: 80, height: 80, - child: MihButton( - onPressed: () {}, - buttonColor: MihColors.getGreyColor( + onPressed: () {}, + buttonColor: MihColors.getGreyColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + child: Icon( + Icons.star_rate_rounded, + color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - child: Icon( - Icons.star_rate_rounded, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - size: iconSize, - ), + size: iconSize, ), ).redacted(context: context, redact: true), const SizedBox(height: 2), @@ -396,24 +382,22 @@ class _MihBusinessCardV2State extends State { } return Column( children: [ - SizedBox( + MihButton( width: 80, height: 80, - child: MihButton( - onPressed: () { - businessReviewRatingWindow(directoryProvider, - businessReview, true, widget.width); - }, - buttonColor: MihColors.getYellowColor( + onPressed: () { + businessReviewRatingWindow(directoryProvider, + businessReview, true, widget.width); + }, + buttonColor: MihColors.getYellowColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + child: Icon( + Icons.star_rate_rounded, + color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - child: Icon( - Icons.star_rate_rounded, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - size: iconSize, - ), + size: iconSize, ), ), const SizedBox(height: 2), @@ -440,21 +424,19 @@ class _MihBusinessCardV2State extends State { if (asyncSnapshot.connectionState == ConnectionState.waiting) { return Column( children: [ - SizedBox( + MihButton( width: 80, height: 80, - child: MihButton( - onPressed: () {}, - buttonColor: MihColors.getGreyColor( + onPressed: () {}, + buttonColor: MihColors.getGreyColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + child: Icon( + Icons.bookmark_add_rounded, + color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - child: Icon( - Icons.bookmark_add_rounded, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - size: iconSize, - ), + size: iconSize, ), ).redacted(context: context, redact: true), const SizedBox(height: 2), @@ -482,29 +464,27 @@ class _MihBusinessCardV2State extends State { } return Column( children: [ - SizedBox( + MihButton( width: 80, height: 80, - child: MihButton( - onPressed: () { - if (bookmarkBusiness == null) { - showAddBookmarkAlert(); - } else { - showDeleteBookmarkAlert(bookmarkBusiness); - } - }, - buttonColor: MihColors.getBluishPurpleColor( + onPressed: () { + if (bookmarkBusiness == null) { + showAddBookmarkAlert(); + } else { + showDeleteBookmarkAlert(bookmarkBusiness); + } + }, + buttonColor: MihColors.getBluishPurpleColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + child: Icon( + bookmarkBusiness == null + ? Icons.bookmark_add_rounded + : Icons.bookmark_remove_rounded, + color: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - child: Icon( - bookmarkBusiness == null - ? Icons.bookmark_add_rounded - : Icons.bookmark_remove_rounded, - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - size: iconSize, - ), + size: iconSize, ), ), const SizedBox(height: 2), diff --git a/mih_ui/lib/mih_package_components/mih_profile_links.dart b/mih_ui/lib/mih_package_components/mih_profile_links.dart index d9457cb3..756edfe1 100644 --- a/mih_ui/lib/mih_package_components/mih_profile_links.dart +++ b/mih_ui/lib/mih_package_components/mih_profile_links.dart @@ -10,12 +10,10 @@ import 'package:url_launcher/url_launcher.dart'; class MihProfileLinks extends StatefulWidget { final List links; - final double? buttonSize; final bool? paddingOn; const MihProfileLinks({ super.key, required this.links, - this.buttonSize, this.paddingOn, }); @@ -83,6 +81,8 @@ class _MihProfileLinksState extends State { MzansiInnovationHub.of(context)!.theme.mode == "Dark"); } return MihButton( + width: 80, + height: 80, onPressed: () { launchSocialUrl(Uri.parse(link.web_link)); }, @@ -90,7 +90,7 @@ class _MihProfileLinksState extends State { child: FaIcon( iconData, color: iconColor, - size: 33, + size: 40, ), ); // return MihPackageTile( @@ -148,11 +148,7 @@ class _MihProfileLinksState extends State { spacing: 10, children: widget.links.map( (link) { - return SizedBox( - width: widget.buttonSize ?? 80, - height: widget.buttonSize ?? 80, - child: displayLinkButton(link), - ); + return displayLinkButton(link); }, ).toList(), ), From f137ea41ac92c7efdabe1e9465582536fd85b99a Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 18 Feb 2026 10:41:49 +0200 Subject: [PATCH 19/31] fix loading indicator alignment for business QR code --- .../mih_business_info_card_v2.dart | 8 +++---- .../mih_loading_circle.dart | 22 ++++++++----------- .../package_tools/mih_business_qr_code.dart | 4 +++- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/mih_ui/lib/mih_package_components/mih_business_info_card_v2.dart b/mih_ui/lib/mih_package_components/mih_business_info_card_v2.dart index 30ec1fb9..2c9684d7 100644 --- a/mih_ui/lib/mih_package_components/mih_business_info_card_v2.dart +++ b/mih_ui/lib/mih_package_components/mih_business_info_card_v2.dart @@ -368,8 +368,8 @@ class _MihBusinessCardV2State extends State { "Dark"), fontSize: 20, ), - ), - ).redacted(context: context, redact: true), + ).redacted(context: context, redact: true), + ), ], ); } else { @@ -450,8 +450,8 @@ class _MihBusinessCardV2State extends State { "Dark"), fontSize: 20, ), - ), - ).redacted(context: context, redact: true), + ).redacted(context: context, redact: true), + ), ], ); } else { diff --git a/mih_ui/lib/mih_package_components/mih_loading_circle.dart b/mih_ui/lib/mih_package_components/mih_loading_circle.dart index 5e9f76c2..576a425a 100644 --- a/mih_ui/lib/mih_package_components/mih_loading_circle.dart +++ b/mih_ui/lib/mih_package_components/mih_loading_circle.dart @@ -19,9 +19,6 @@ class _MihloadingcircleState extends State late AnimationController _controller; late Animation _animation; - late double width; - late double height; - @override void initState() { super.initState(); @@ -82,16 +79,15 @@ class _MihloadingcircleState extends State }, ), ), - widget.message != null - ? Text( - widget.message!, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ) - : SizedBox(), + if (widget.message != null) + Text( + widget.message!, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), ], )), ), diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart index 1313b177..d628d3de 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart @@ -298,7 +298,9 @@ class _MihBusinessQrCodeState extends State { height: 300, child: CachedNetworkImage( imageUrl: getQrCodeData(qrSize.toInt()), - placeholder: (context, url) => const Mihloadingcircle(), + placeholder: (context, url) => FittedBox( + child: const Mihloadingcircle(), + ), errorWidget: (context, url, error) => const Icon(Icons.error), ), From 3f0fc08a5c02a0cdfb697279f8be8af216690b2a Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 18 Feb 2026 10:56:34 +0200 Subject: [PATCH 20/31] update business user edit workflow --- .../mih_update_my_business_user_details.dart | 378 ++++++++++-------- .../package_tools/mih_my_business_user.dart | 75 ++-- 2 files changed, 245 insertions(+), 208 deletions(-) diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_my_business_user_details.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_my_business_user_details.dart index e716f07a..7217dbc7 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_my_business_user_details.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_my_business_user_details.dart @@ -5,7 +5,6 @@ import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_button.dart'; -import 'package:mzansi_innovation_hub/mih_package_components/mih_circle_avatar.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_form.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_image_display.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_package_window.dart'; @@ -133,185 +132,218 @@ class _MihUpdateMyBusinessUserDetailsState MzansiInnovationHub.of(context)!.theme.screenType == "desktop" ? EdgeInsets.symmetric(horizontal: width * 0.2) : EdgeInsets.symmetric(horizontal: width * 0.075), - child: Column( + child: Stack( children: [ - MihForm( - formKey: _formKey, - formFields: [ - Center( - child: MihCircleAvatar( - imageFile: mzansiProfileProvider.userProfilePicture, - width: 150, - editable: false, - fileNameController: fileNameController, - userSelectedfile: userPicFile, - frameColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - backgroundColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - onChange: (_) {}, - ), - ), - Visibility( - visible: false, - child: MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: fileNameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Selected File Name", - ), - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: titleTextController, - multiLineInput: false, - requiredText: true, - readOnly: false, - hintText: "Title", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: fnameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "First Name", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: lnameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Surname", - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10), - MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: accessController, - multiLineInput: false, - requiredText: true, - hintText: "Access Level", - readOnly: true, - validator: (value) { - return MihValidationServices().isEmpty(value); - }, - ), - const SizedBox(height: 10), - Container( - width: 300, - alignment: Alignment.topLeft, - child: const Text( - "Signature:", - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - ), - ), - ), - Center( - child: MihImageDisplay( - imageFile: newSelectedSignaturePic != null - ? MemoryImage(newSelectedSignaturePic!.bytes!) - : mzansiProfileProvider.businessUserSignature, - width: 300, - height: 200, - editable: true, - fileNameController: signtureController, - userSelectedfile: newSelectedSignaturePic, - onChange: (selectedFile) { - setState(() { - newSelectedSignaturePic = selectedFile; - }); - }, - ), - ), - const SizedBox(height: 10), - Visibility( - visible: false, - child: MihTextFormField( - fillColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - inputColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - controller: fileNameController, - multiLineInput: false, - requiredText: true, - readOnly: true, - hintText: "Selected Signature File", - ), - ), - const SizedBox(height: 15), - Center( - child: MihButton( - onPressed: () { - if (_formKey.currentState!.validate()) { - submitForm(mzansiProfileProvider); - } else { - MihAlertServices().inputErrorAlert(context); - } - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - width: 300, - child: Text( - "Update", - style: TextStyle( - color: MihColors.getPrimaryColor( + Column( + children: [ + MihForm( + formKey: _formKey, + formFields: [ + // Center( + // child: MihCircleAvatar( + // imageFile: mzansiProfileProvider.userProfilePicture, + // width: 150, + // editable: false, + // fileNameController: fileNameController, + // userSelectedfile: userPicFile, + // frameColor: MihColors.getSecondaryColor( + // MzansiInnovationHub.of(context)!.theme.mode == + // "Dark"), + // backgroundColor: MihColors.getPrimaryColor( + // MzansiInnovationHub.of(context)!.theme.mode == + // "Dark"), + // onChange: (_) {}, + // ), + // ), + Visibility( + visible: false, + child: MihTextFormField( + fillColor: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: fileNameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Selected File Name", ), ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: titleTextController, + multiLineInput: false, + requiredText: true, + readOnly: false, + hintText: "Title", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: fnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "First Name", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: lnameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Surname", + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: accessController, + multiLineInput: false, + requiredText: true, + hintText: "Access Level", + readOnly: true, + validator: (value) { + return MihValidationServices().isEmpty(value); + }, + ), + const SizedBox(height: 10), + Container( + width: 300, + alignment: Alignment.topLeft, + child: const Text( + "Signature:", + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ), + Center( + child: MihImageDisplay( + imageFile: newSelectedSignaturePic != null + ? MemoryImage(newSelectedSignaturePic!.bytes!) + : mzansiProfileProvider.businessUserSignature, + width: 300, + height: 200, + editable: true, + fileNameController: signtureController, + userSelectedfile: newSelectedSignaturePic, + onChange: (selectedFile) { + setState(() { + newSelectedSignaturePic = selectedFile; + }); + }, + ), + ), + const SizedBox(height: 10), + Visibility( + visible: false, + child: MihTextFormField( + fillColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + inputColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + controller: fileNameController, + multiLineInput: false, + requiredText: true, + readOnly: true, + hintText: "Selected Signature File", + ), + ), + const SizedBox(height: 15), + Center( + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitForm(mzansiProfileProvider); + } else { + MihAlertServices().inputErrorAlert(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 300, + child: Text( + "Update", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + const SizedBox(height: 20), + ], + ), + ], + ), + Positioned( + top: 0, + right: 0, + child: MihButton( + onPressed: () { + if (_formKey.currentState!.validate()) { + submitForm(mzansiProfileProvider); + } else { + MihAlertServices().inputErrorAlert(context); + } + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + width: 100, + height: 25, + child: Text( + "Update", + style: TextStyle( + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + fontSize: 15, + fontWeight: FontWeight.bold, ), ), - const SizedBox(height: 20), - ], + ), ), ], ), diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart index 27ceb514..3de6a8b9 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart @@ -184,19 +184,46 @@ class _MihMyBusinessUserState extends State { child: Column( children: [ Center( - child: MihCircleAvatar( - imageFile: mzansiProfileProvider.userProfilePicture, - width: 150, - editable: false, - fileNameController: fileNameController, - userSelectedfile: userPicFile, - frameColor: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - backgroundColor: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - onChange: (_) {}, + child: Stack( + children: [ + MihCircleAvatar( + imageFile: mzansiProfileProvider.userProfilePicture, + width: 150, + editable: false, + fileNameController: fileNameController, + userSelectedfile: userPicFile, + frameColor: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + backgroundColor: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + onChange: (_) {}, + ), + Positioned( + bottom: 5, + right: 5, + child: MihButton( + onPressed: () { + editBizUserProfileWindow( + mzansiProfileProvider, width); + }, + buttonColor: MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + width: 35, + height: 35, + child: Icon( + Icons.edit, + color: MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark"), + ), + ), + ), + ], ), ), const SizedBox(height: 20), @@ -246,28 +273,6 @@ class _MihMyBusinessUserState extends State { ), ), const SizedBox(height: 20), - Center( - child: MihButton( - onPressed: () { - editBizUserProfileWindow( - mzansiProfileProvider, width); - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - width: 300, - child: Text( - "Edit Profile", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == - "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), - ), ], ), ), From 82c25c54065df5317c313f096d26c883da27d475 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 18 Feb 2026 11:51:44 +0200 Subject: [PATCH 21/31] make profile picture expandable --- .../package_tools/package_tool_one.dart | 1 + .../mih_business_profile_preview.dart | 1 + .../mih_circle_avatar.dart | 218 ++++++++++-------- .../mih_personal_profile_preview.dart | 1 + .../mih_home/components/mih_app_drawer.dart | 1 + .../lib/mih_packages/mih_home/mih_home.dart | 1 + .../build_minesweeper_leaderboard_list.dart | 1 + .../components/leaderboard_user_ranking.dart | 1 + .../package_tools/my_score_board.dart | 1 + .../mih_update_business_details_window.dart | 1 + .../package_tools/mih_business_details.dart | 1 + .../mih_business_details_set_up.dart | 1 + .../mih_business_details_view.dart | 1 + .../package_tools/mih_business_qr_code.dart | 1 + .../package_tools/mih_my_business_user.dart | 1 + .../mih_edit_personal_profile_window.dart | 1 + .../package_tools/mih_personal_profile.dart | 1 + .../mih_personal_profile_view.dart | 1 + .../package_tools/patient_info.dart | 1 + 19 files changed, 138 insertions(+), 98 deletions(-) diff --git a/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_one.dart b/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_one.dart index 67404fcf..47364ef8 100644 --- a/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_one.dart +++ b/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_one.dart @@ -774,6 +774,7 @@ class _PackageToolOneState extends State { MihCircleAvatar( imageFile: imagePreview, width: 50, + expandable: true, editable: false, fileNameController: _fileNameController, userSelectedfile: file, diff --git a/mih_ui/lib/mih_package_components/mih_business_profile_preview.dart b/mih_ui/lib/mih_package_components/mih_business_profile_preview.dart index 81cdcf6b..0380688e 100644 --- a/mih_ui/lib/mih_package_components/mih_business_profile_preview.dart +++ b/mih_ui/lib/mih_package_components/mih_business_profile_preview.dart @@ -68,6 +68,7 @@ class _MihBusinessProfilePreviewState extends State { : MihCircleAvatar( imageFile: widget.imageFile, width: profilePictureWidth, + expandable: false, editable: false, fileNameController: TextEditingController(), userSelectedfile: null, diff --git a/mih_ui/lib/mih_package_components/mih_circle_avatar.dart b/mih_ui/lib/mih_package_components/mih_circle_avatar.dart index c44c72a3..f9369d30 100644 --- a/mih_ui/lib/mih_package_components/mih_circle_avatar.dart +++ b/mih_ui/lib/mih_package_components/mih_circle_avatar.dart @@ -2,13 +2,17 @@ import 'dart:io'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; +import 'package:mzansi_innovation_hub/mih_package_components/mih_package_window.dart'; class MihCircleAvatar extends StatefulWidget { final ImageProvider? imageFile; final double width; + final bool expandable; final bool editable; final TextEditingController? fileNameController; final onChange; @@ -19,6 +23,7 @@ class MihCircleAvatar extends StatefulWidget { super.key, required this.imageFile, required this.width, + required this.expandable, required this.editable, required this.fileNameController, required this.userSelectedfile, @@ -35,23 +40,30 @@ class _MihCircleAvatarState extends State { late ImageProvider? imagePreview; ImageProvider? getAvatar() { - // Color dark = const Color(0XFF3A4454); if (widget.imageFile == null) { return null; - // if (widget.backgroundColor == dark) { - // print("here in light icon"); - // return const AssetImage( - // 'lib/mih_package_components/assets/images/i-dont-know-light.png'); - // } else { - // print("here in dark icon"); - // return const AssetImage( - // 'lib/mih_package_components/assets/images/i-dont-know-dark.png'); - // } } else { return widget.imageFile; } } + void expandAvatar() { + showDialog( + context: context, + builder: (context) { + return MihPackageWindow( + fullscreen: false, + windowTitle: "", + onWindowTapClose: () { + context.pop(); + }, + windowBody: InteractiveViewer( + child: Image(image: imagePreview!), + ), + ); + }); + } + @override void initState() { super.initState(); @@ -62,111 +74,121 @@ class _MihCircleAvatarState extends State { @override Widget build(BuildContext context) { - return Container( - // color: Colors.white, - alignment: Alignment.center, - width: widget.width, - height: widget.width, - child: Stack( + return GestureDetector( + onTap: widget.expandable + ? () { + KenLogger.success("Avatar tapped"); + expandAvatar(); + } + : null, + child: Container( alignment: Alignment.center, - children: [ - Visibility( - visible: imagePreview != null, - child: Positioned( - right: widget.width * 0.03, - child: CircleAvatar( - radius: widget.width / 2.2, - backgroundColor: widget.backgroundColor, - backgroundImage: imagePreview, + width: widget.width, + height: widget.width, + child: Stack( + alignment: Alignment.center, + children: [ + Visibility( + visible: imagePreview != null, + child: Positioned( + right: widget.width * 0.03, + child: CircleAvatar( + radius: widget.width / 2.2, + backgroundColor: widget.backgroundColor, + backgroundImage: imagePreview, + ), ), ), - ), - Visibility( - visible: imagePreview != null, - child: Icon( - size: widget.width, - MihIcons.mihRing, - color: widget.frameColor, + Visibility( + visible: imagePreview != null, + child: Icon( + size: widget.width, + MihIcons.mihRing, + color: widget.frameColor, + ), ), - ), - Visibility( - visible: imagePreview == null, - child: Icon( - MihIcons.iDontKnow, - size: widget.width, - color: widget.frameColor, + Visibility( + visible: imagePreview == null, + child: Icon( + MihIcons.iDontKnow, + size: widget.width, + color: widget.frameColor, + ), ), - ), - Visibility( - visible: widget.editable, - child: Positioned( - bottom: 0, - right: 0, - child: IconButton.filled( - style: ButtonStyle( - backgroundColor: WidgetStateProperty.all( - MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + Visibility( + visible: widget.editable, + child: Positioned( + bottom: 0, + right: 0, + child: IconButton.filled( + style: ButtonStyle( + backgroundColor: WidgetStateProperty.all( + MihColors.getGreenColor( + MzansiInnovationHub.of(context)!.theme.mode == + "Dark"), + ), ), - ), - onPressed: () async { - try { - FilePickerResult? result = - await FilePicker.platform.pickFiles( - type: FileType.image, - ); - // print("Here 1"); - if (MzansiInnovationHub.of(context)!.theme.getPlatform() == - "Web") { - // print("Here 2"); - if (result == null) return; - // print("Here 3"); - PlatformFile? selectedFile = result.files.first; - setState(() { - // print("Here 4"); - widget.onChange(selectedFile); - // print("Here 5"); - imagePreview = MemoryImage(selectedFile.bytes!); - }); - - setState(() { - widget.fileNameController!.text = selectedFile.name; - }); - } else { - if (result != null) { - File file = File(result.files.single.path!); - PlatformFile? androidFile = PlatformFile( - path: file.path, - name: file.path.split('/').last, - size: file.lengthSync(), - bytes: await file.readAsBytes(), // Read file bytes - //extension: fileExtension, - ); + onPressed: () async { + try { + FilePickerResult? result = + await FilePicker.platform.pickFiles( + type: FileType.image, + ); + // print("Here 1"); + if (MzansiInnovationHub.of(context)! + .theme + .getPlatform() == + "Web") { + // print("Here 2"); + if (result == null) return; + // print("Here 3"); + PlatformFile? selectedFile = result.files.first; setState(() { - widget.onChange(androidFile); - imagePreview = FileImage(file); + // print("Here 4"); + widget.onChange(selectedFile); + // print("Here 5"); + imagePreview = MemoryImage(selectedFile.bytes!); }); setState(() { - widget.fileNameController!.text = - file.path.split('/').last; + widget.fileNameController!.text = selectedFile.name; }); } else { - print("here in else"); - // User canceled the picker + if (result != null) { + File file = File(result.files.single.path!); + PlatformFile? androidFile = PlatformFile( + path: file.path, + name: file.path.split('/').last, + size: file.lengthSync(), + bytes: await file.readAsBytes(), // Read file bytes + //extension: fileExtension, + ); + setState(() { + widget.onChange(androidFile); + imagePreview = FileImage(file); + }); + + setState(() { + widget.fileNameController!.text = + file.path.split('/').last; + }); + } else { + print("here in else"); + // User canceled the picker + } } + } catch (e) { + print("Here Error: $e"); } - } catch (e) { - print("Here Error: $e"); - } - }, - icon: Icon( - Icons.camera_alt, + }, + icon: Icon( + Icons.camera_alt, + ), ), ), ), - ), - ], + ], + ), ), ); } diff --git a/mih_ui/lib/mih_package_components/mih_personal_profile_preview.dart b/mih_ui/lib/mih_package_components/mih_personal_profile_preview.dart index 1b562f81..daf313af 100644 --- a/mih_ui/lib/mih_package_components/mih_personal_profile_preview.dart +++ b/mih_ui/lib/mih_package_components/mih_personal_profile_preview.dart @@ -49,6 +49,7 @@ class _MihPersonalProfilePreviewState extends State { : MihCircleAvatar( imageFile: widget.imageFile, width: profilePictureWidth, + expandable: false, editable: false, fileNameController: TextEditingController(), userSelectedfile: null, diff --git a/mih_ui/lib/mih_packages/mih_home/components/mih_app_drawer.dart b/mih_ui/lib/mih_packages/mih_home/components/mih_app_drawer.dart index 45a0e89f..71ec53f7 100644 --- a/mih_ui/lib/mih_packages/mih_home/components/mih_app_drawer.dart +++ b/mih_ui/lib/mih_packages/mih_home/components/mih_app_drawer.dart @@ -78,6 +78,7 @@ class _MIHAppDrawerState extends State { ? mzansiProfileProvider.userProfilePicture : mzansiProfileProvider.businessProfilePicture, width: 60, + expandable: false, editable: false, fileNameController: proPicController, onChange: (_) {}, diff --git a/mih_ui/lib/mih_packages/mih_home/mih_home.dart b/mih_ui/lib/mih_packages/mih_home/mih_home.dart index f3f49482..aaa59ed2 100644 --- a/mih_ui/lib/mih_packages/mih_home/mih_home.dart +++ b/mih_ui/lib/mih_packages/mih_home/mih_home.dart @@ -353,6 +353,7 @@ class _MihHomeState extends State { key: Key(imageKey), imageFile: currentImage, width: 50, + expandable: false, editable: false, fileNameController: null, userSelectedfile: null, diff --git a/mih_ui/lib/mih_packages/mine_sweeper/builders/build_minesweeper_leaderboard_list.dart b/mih_ui/lib/mih_packages/mine_sweeper/builders/build_minesweeper_leaderboard_list.dart index 7f870c46..2b9ed288 100644 --- a/mih_ui/lib/mih_packages/mine_sweeper/builders/build_minesweeper_leaderboard_list.dart +++ b/mih_ui/lib/mih_packages/mine_sweeper/builders/build_minesweeper_leaderboard_list.dart @@ -104,6 +104,7 @@ class _BuildMinesweeperLeaderboardListState key: UniqueKey(), imageFile: imageFile, width: 80, + expandable: true, editable: false, fileNameController: null, userSelectedfile: null, diff --git a/mih_ui/lib/mih_packages/mine_sweeper/components/leaderboard_user_ranking.dart b/mih_ui/lib/mih_packages/mine_sweeper/components/leaderboard_user_ranking.dart index 4bd48355..338189b7 100644 --- a/mih_ui/lib/mih_packages/mine_sweeper/components/leaderboard_user_ranking.dart +++ b/mih_ui/lib/mih_packages/mine_sweeper/components/leaderboard_user_ranking.dart @@ -50,6 +50,7 @@ class LeaderboardUserRanking extends StatelessWidget { .toString()), // Use ValueKey for stable identity imageFile: asyncSnapshot.data, width: 60, + expandable: true, editable: false, fileNameController: null, userSelectedfile: null, diff --git a/mih_ui/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart b/mih_ui/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart index 31e18824..25433358 100644 --- a/mih_ui/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart +++ b/mih_ui/lib/mih_packages/mine_sweeper/package_tools/my_score_board.dart @@ -87,6 +87,7 @@ class _MihMineSweeperLeaderBoardState extends State { child: MihCircleAvatar( imageFile: profileProvider.userProfilePicture, width: 150, + expandable: true, editable: false, fileNameController: null, userSelectedfile: null, diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart index 553c31d3..80f294ec 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/components/mih_update_business_details_window.dart @@ -271,6 +271,7 @@ class _MihUpdateBusinessDetailsWindowState : mzansiProfileProvider .businessProfilePicture, width: 150, + expandable: false, editable: true, fileNameController: fileNameController, userSelectedfile: newSelectedLogoPic, diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart index 8ac92d58..9b5df943 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details.dart @@ -77,6 +77,7 @@ class _MihBusinessDetailsState extends State { imageFile: mzansiProfileProvider.businessProfilePicture, width: 150, + expandable: true, editable: false, fileNameController: fileNameController, userSelectedfile: newSelectedLogoPic, diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_set_up.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_set_up.dart index e7d976e7..9564774e 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_set_up.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_set_up.dart @@ -330,6 +330,7 @@ class _MihBusinessDetailsSetUpState extends State { ? MemoryImage(newSelectedLogoPic!.bytes!) : mzansiProfileProvider.businessProfilePicture, width: 150, + expandable: false, editable: true, fileNameController: logoFileNameController, userSelectedfile: newSelectedLogoPic, diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart index bf03da5d..5663c9d7 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_details_view.dart @@ -77,6 +77,7 @@ class _MihBusinessDetailsViewState extends State { imageFile: CachedNetworkImageProvider( asyncSnapshot.requireData), width: profilePictureWidth, + expandable: true, editable: false, fileNameController: TextEditingController(), userSelectedfile: file, diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart index d628d3de..4d6fd736 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart @@ -211,6 +211,7 @@ class _MihBusinessQrCodeState extends State { imageFile: CachedNetworkImageProvider( asyncSnapshot.requireData), width: profilePictureWidth, + expandable: true, editable: false, fileNameController: TextEditingController(), userSelectedfile: file, diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart index 3de6a8b9..db4e2235 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_my_business_user.dart @@ -189,6 +189,7 @@ class _MihMyBusinessUserState extends State { MihCircleAvatar( imageFile: mzansiProfileProvider.userProfilePicture, width: 150, + expandable: true, editable: false, fileNameController: fileNameController, userSelectedfile: userPicFile, diff --git a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart index 7680088c..5fb60204 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/components/mih_edit_personal_profile_window.dart @@ -343,6 +343,7 @@ class _MihEditPersonalProfileWindowState ? MemoryImage(newSelectedProPic!.bytes!) : mzansiProfileProvider.userProfilePicture, width: 150, + expandable: false, editable: true, fileNameController: proPicController, userSelectedfile: newSelectedProPic, diff --git a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart index c579c106..622a3adc 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile.dart @@ -160,6 +160,7 @@ class _MihPersonalProfileState extends State { MihCircleAvatar( imageFile: mzansiProfileProvider.userProfilePicture, width: 150, + expandable: true, editable: false, fileNameController: proPicController, userSelectedfile: newSelectedProPic, diff --git a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart index 212df873..1b39d6fa 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/personal_profile/package_tools/mih_personal_profile_view.dart @@ -74,6 +74,7 @@ class _MihPersonalProfileViewState extends State { imageFile: CachedNetworkImageProvider( asyncSnapshot.requireData), width: profilePictureWidth, + expandable: true, editable: false, fileNameController: TextEditingController(), userSelectedfile: file, diff --git a/mih_ui/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart b/mih_ui/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart index 283b2ac6..01a80abd 100644 --- a/mih_ui/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart +++ b/mih_ui/lib/mih_packages/patient_manager/pat_profile/package_tools/patient_info.dart @@ -314,6 +314,7 @@ class _PatientInfoState extends State { imageFile: patientManagerProvider.selectedPatientProfilePicture, width: 160, + expandable: true, editable: false, fileNameController: null, userSelectedfile: null, From ebab9bae524c79c5cf64138786c5cf53f2e453ad Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 18 Feb 2026 11:52:30 +0200 Subject: [PATCH 22/31] update build no to 128 --- mih_ui/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mih_ui/pubspec.yaml b/mih_ui/pubspec.yaml index 6d2db76a..cb6c34bc 100644 --- a/mih_ui/pubspec.yaml +++ b/mih_ui/pubspec.yaml @@ -1,7 +1,7 @@ name: mzansi_innovation_hub description: "" publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 1.2.6+127 +version: 1.2.6+128 # version: 1.1.1+97 #--- Updated version for upgrader package testing environment: From e33a62b9093c2dfd33198c540a1eedcb449c5e36 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 18 Feb 2026 14:03:04 +0200 Subject: [PATCH 23/31] update look & feel of attribution list --- .../package_tools/mih_ attributes.dart | 240 ++++-------------- 1 file changed, 45 insertions(+), 195 deletions(-) diff --git a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_ attributes.dart b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_ attributes.dart index d1948fef..d1918fbb 100644 --- a/mih_ui/lib/mih_packages/about_mih/package_tools/mih_ attributes.dart +++ b/mih_ui/lib/mih_packages/about_mih/package_tools/mih_ attributes.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_single_child_scroll.dart'; -import 'package:mzansi_innovation_hub/mih_package_components/mih_button.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tool_body.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_icons.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; @@ -21,72 +20,30 @@ class _MihAttributesState extends State { } } - TableRow displayIcon(IconData icon, String creator, String link) { - return TableRow( - children: [ - TableCell( - verticalAlignment: TableCellVerticalAlignment.middle, - child: SizedBox( - height: 150, - child: Padding( - padding: const EdgeInsets.only(bottom: 15.0), - child: FittedBox( - child: Center( - child: Icon( - icon, - // size: 125, - color: MihColors.getSecondaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - ), - ), - ), - ), + Widget displayAttribution(IconData resource, String creator, String link) { + return GestureDetector( + onTap: () { + launchUrlLink( + Uri.parse( + link, ), - ), - TableCell( - verticalAlignment: TableCellVerticalAlignment.middle, - child: Padding( - padding: const EdgeInsets.all(15.0), - child: Center( - child: Text( - creator, - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), + ); + }, + child: Column( + children: [ + Icon( + resource, + color: MihColors.getSecondaryColor( + MzansiInnovationHub.of(context)!.theme.mode == "Dark"), + size: 100, ), - ), - TableCell( - verticalAlignment: TableCellVerticalAlignment.middle, - child: Padding( - padding: const EdgeInsets.only(bottom: 15.0), - child: MihButton( - onPressed: () { - launchUrlLink( - Uri.parse( - link, - ), - ); - }, - buttonColor: MihColors.getGreenColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - width: 100, - child: Text( - "Visit", - style: TextStyle( - color: MihColors.getPrimaryColor( - MzansiInnovationHub.of(context)!.theme.mode == "Dark"), - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - ), + const SizedBox(height: 5), + Text( + creator, + style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold), ), - ), - ], + ], + ), ); } @@ -132,157 +89,50 @@ class _MihAttributesState extends State { height: 10, ), SizedBox( - width: 700, - child: Table( - defaultVerticalAlignment: TableCellVerticalAlignment.middle, - columnWidths: const { - 0: FlexColumnWidth(1), - 1: FlexColumnWidth(1), - 2: FlexColumnWidth(1), - }, + width: 900, + child: Wrap( + alignment: WrapAlignment.center, + runSpacing: 10, + spacing: 10, children: [ - const TableRow( - children: [ - TableCell( - verticalAlignment: TableCellVerticalAlignment.middle, - child: Padding( - padding: const EdgeInsets.only(bottom: 15.0), - child: Center( - child: Text( - "Resources", - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), - TableCell( - verticalAlignment: TableCellVerticalAlignment.middle, - child: Padding( - padding: const EdgeInsets.only(bottom: 15.0), - child: Center( - child: Text( - "Creator", - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), - TableCell( - child: Padding( - padding: const EdgeInsets.only(bottom: 15.0), - child: Center( - child: Text( - "Link", - style: TextStyle( - fontSize: 25, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - ), - ], - ), - displayIcon(MihIcons.mihRing, "Tarah Meth", + displayAttribution(MihIcons.mihRing, "Tarah Meth", "https://www.linkedin.com/in/tarah-meth-3b6309254/"), - displayIcon(MihIcons.mihLogo, "Tarah Meth", + displayAttribution(MihIcons.mihLogo, "Tarah Meth", "https://www.linkedin.com/in/tarah-meth-3b6309254/"), - displayIcon( + displayAttribution( MihIcons.mzansiAi, "Ollama", "https://ollama.com/"), - displayIcon(MihIcons.mzansiWallet, "Freepik", + displayAttribution(MihIcons.mzansiWallet, "Freepik", "https://www.flaticon.com/free-icon/wallet-passes-app_3884407?term=wallet&page=1&position=21&origin=search&related_id=3884407"), - displayIcon(MihIcons.patientProfile, "RaftelDesign", + displayAttribution(MihIcons.patientProfile, "RaftelDesign", "https://www.flaticon.com/free-icon/patient_2376100?term=medication&page=1&position=6&origin=search&related_id=2376100"), - displayIcon(MihIcons.patientProfile, "Srip", + displayAttribution(MihIcons.patientProfile, "Srip", "https://www.flaticon.com/free-icon/hospital_1233930?term=medical+snake&page=1&position=7&origin=search&related_id=1233930"), - displayIcon(MihIcons.calendar, "Freepik", + displayAttribution(MihIcons.calendar, "Freepik", "https://www.flaticon.com/free-icon/calendar_2278049?term=calendar&page=1&position=5&origin=search&related_id=2278049"), - displayIcon(MihIcons.calculator, "Freepik", + displayAttribution(MihIcons.calculator, "Freepik", "https://www.flaticon.com/free-icon/calculator_2374409?term=calculator&page=1&position=20&origin=search&related_id=2374409"), - displayIcon(MihIcons.aboutMih, "Chanut", + displayAttribution(MihIcons.aboutMih, "Chanut", "https://www.flaticon.com/free-icon/info_151776?term=about&page=1&position=8&origin=search&related_id=151776"), - displayIcon(MihIcons.personalProfile, "Freepik", + displayAttribution(MihIcons.personalProfile, "Freepik", "https://www.flaticon.com/free-icon/user_1077063?term=profile&page=1&position=6&origin=search&related_id=1077063"), - displayIcon(MihIcons.businessProfile, "Gravisio", + displayAttribution(MihIcons.businessProfile, "Gravisio", "https://www.flaticon.com/free-icon/contractor_11813336?term=company+profile&page=1&position=2&origin=search&related_id=11813336"), - displayIcon(MihIcons.patientManager, "Vector Tank", + displayAttribution(MihIcons.patientManager, "Vector Tank", "https://www.flaticon.com/free-icon/doctor_10215061?term=doctor&page=1&position=73&origin=search&related_id=10215061"), - displayIcon(MihIcons.profileSetup, "Freepik", + displayAttribution(MihIcons.profileSetup, "Freepik", "https://www.flaticon.com/free-icon/add-user_748137?term=profile+add&page=1&position=1&origin=search&related_id=748137"), - displayIcon(MihIcons.businessSetup, "kerismaker", + displayAttribution(MihIcons.businessSetup, "kerismaker", "https://www.flaticon.com/free-icon/business_13569850?term=company+add&page=1&position=25&origin=search&related_id=13569850"), - displayIcon(MihIcons.calculator, "fawazahmed0", + displayAttribution(MihIcons.calculator, "fawazahmed0", "https://github.com/fawazahmed0/exchange-api"), - displayIcon(MihIcons.iDontKnow, "Freepik", + displayAttribution(MihIcons.iDontKnow, "Freepik", "https://www.flaticon.com/free-icon/i-dont-know_5359909?term=i+dont+know&page=1&position=7&origin=search&related_id=5359909"), ], ), ), - // SizedBox( - // width: 500, - // child: Column( - // children: [ - // const SizedBox( - // width: double.infinity, - // child: Row( - // mainAxisAlignment: MainAxisAlignment.spaceEvenly, - // mainAxisSize: MainAxisSize.max, - // children: [ - // Flexible( - // child: Text( - // "Icon", - // style: TextStyle( - // fontSize: 25, - // fontWeight: FontWeight.bold, - // ), - // ), - // ), - // Flexible( - // child: Text( - // "Creator", - // style: TextStyle( - // fontSize: 25, - // fontWeight: FontWeight.bold, - // ), - // ), - // ), - // Flexible( - // child: Text( - // "Link", - // style: TextStyle( - // fontSize: 25, - // fontWeight: FontWeight.bold, - // ), - // ), - // ), - // ], - // ), - // ), - // const Padding( - // padding: EdgeInsets.symmetric(vertical: 10.0), - // child: Divider(), - // ), - // displayIcon(MihIcons.mihLogo, "Tarah Meth", - // "https://app.mzansi-innovation-hub.co.za/"), - // const SizedBox(height: 10), - // displayIcon(MihIcons.mihLogo, "Test", - // "https://www.flaticon.com/free-icons/mih"), - // const SizedBox(height: 10), - // displayIcon(MihIcons.mihLogo, "Test", - // "https://www.flaticon.com/free-icons/mih"), - // const SizedBox(height: 10), - // displayIcon(MihIcons.mihLogo, "Test", - // "https://www.flaticon.com/free-icons/mih"), - // const SizedBox(height: 10), - // ], - // ), - // ) + const SizedBox( + height: 30, + ), ], ), ), From 213f3d418d18d52a647a297453ad35a1ec5039f6 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 18 Feb 2026 15:41:37 +0200 Subject: [PATCH 24/31] update build number to 129 --- mih_ui/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mih_ui/pubspec.yaml b/mih_ui/pubspec.yaml index cb6c34bc..f0b73b3e 100644 --- a/mih_ui/pubspec.yaml +++ b/mih_ui/pubspec.yaml @@ -1,7 +1,7 @@ name: mzansi_innovation_hub description: "" publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 1.2.6+128 +version: 1.2.6+129 # version: 1.1.1+97 #--- Updated version for upgrader package testing environment: From 1143d11054f73958df92ddf456e1fd6042219a67 Mon Sep 17 00:00:00 2001 From: yaso Date: Tue, 24 Feb 2026 11:02:30 +0200 Subject: [PATCH 25/31] fix supertoken versioning error --- mih_api_hub/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mih_api_hub/requirements.txt b/mih_api_hub/requirements.txt index 1cca0eba..f3fd0d07 100644 --- a/mih_api_hub/requirements.txt +++ b/mih_api_hub/requirements.txt @@ -9,5 +9,5 @@ watchfiles python-multipart python-dotenv xlrd -supertokens-python +supertokens-python==0.24.0 sniffio \ No newline at end of file From 27639cb964e67fa2aea2d06b99c3f1e184ced527 Mon Sep 17 00:00:00 2001 From: yaso Date: Tue, 24 Feb 2026 11:05:24 +0200 Subject: [PATCH 26/31] add scroll bar to dropdown fields --- .../mih_package_components/mih_dropdwn_field.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/mih_ui/lib/mih_package_components/mih_dropdwn_field.dart b/mih_ui/lib/mih_package_components/mih_dropdwn_field.dart index dd8d46ee..3ec6861f 100644 --- a/mih_ui/lib/mih_package_components/mih_dropdwn_field.dart +++ b/mih_ui/lib/mih_package_components/mih_dropdwn_field.dart @@ -103,6 +103,18 @@ class _MihDropdownFieldState extends State { Expanded( child: Theme( data: Theme.of(context).copyWith( + scrollbarTheme: ScrollbarThemeData( + thumbColor: WidgetStatePropertyAll( + MihColors.getPrimaryColor( + MzansiInnovationHub.of(context)! + .theme + .mode == + "Dark")), + thickness: const WidgetStatePropertyAll(6), + radius: const Radius.circular(10), + thumbVisibility: const WidgetStatePropertyAll( + true), // Always show when scrolling + ), textSelectionTheme: TextSelectionThemeData( cursorColor: MihColors.getPrimaryColor( MzansiInnovationHub.of(context)!.theme.mode == From baea2c9fdbb91f6f360d483205cf09264d1b4323 Mon Sep 17 00:00:00 2001 From: yaso Date: Tue, 24 Feb 2026 12:37:31 +0200 Subject: [PATCH 27/31] fix file display on Dev Web & iOS --- mih_ui/lib/mih_services/mih_file_services.dart | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mih_ui/lib/mih_services/mih_file_services.dart b/mih_ui/lib/mih_services/mih_file_services.dart index c9106c2c..76a15836 100644 --- a/mih_ui/lib/mih_services/mih_file_services.dart +++ b/mih_ui/lib/mih_services/mih_file_services.dart @@ -1,7 +1,10 @@ import 'dart:convert'; +import 'dart:io'; import 'package:file_picker/file_picker.dart'; +import 'package:flutter/foundation.dart'; import 'package:go_router/go_router.dart'; +import 'package:ken_logger/ken_logger.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_loading_circle.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; import 'package:flutter/material.dart'; @@ -51,6 +54,13 @@ class MihFileApi { } finally { // Navigator.of(context).pop(); // Always pop loading dialog } + KenLogger.success("File URL: $fileUrl"); + if (AppEnviroment.getEnv() == "Dev" && isSkiaWeb) { + fileUrl = fileUrl.replaceAll("10.0.2.2", "127.0.0.1"); + } else if (AppEnviroment.getEnv() == "Dev" && Platform.isIOS) { + fileUrl = fileUrl.replaceAll("10.0.2.2", "127.0.0.1"); + } + KenLogger.success("File URL: $fileUrl"); return fileUrl; } From ce2575035f2c57b9c068f84c26e2f69b34e0770c Mon Sep 17 00:00:00 2001 From: yaso Date: Tue, 24 Feb 2026 12:43:34 +0200 Subject: [PATCH 28/31] make profile picture the full height of the window --- .../lib/mih_package_components/mih_circle_avatar.dart | 9 ++++++--- .../lib/mih_package_components/mih_package_window.dart | 10 +++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/mih_ui/lib/mih_package_components/mih_circle_avatar.dart b/mih_ui/lib/mih_package_components/mih_circle_avatar.dart index f9369d30..c3d4db1f 100644 --- a/mih_ui/lib/mih_package_components/mih_circle_avatar.dart +++ b/mih_ui/lib/mih_package_components/mih_circle_avatar.dart @@ -52,13 +52,16 @@ class _MihCircleAvatarState extends State { context: context, builder: (context) { return MihPackageWindow( - fullscreen: false, + fullscreen: true, windowTitle: "", + scrollbarOn: false, onWindowTapClose: () { context.pop(); }, - windowBody: InteractiveViewer( - child: Image(image: imagePreview!), + windowBody: SizedBox.expand( + child: InteractiveViewer( + child: Image(image: imagePreview!), + ), ), ); }); diff --git a/mih_ui/lib/mih_package_components/mih_package_window.dart b/mih_ui/lib/mih_package_components/mih_package_window.dart index cb9afb40..77f6a855 100644 --- a/mih_ui/lib/mih_package_components/mih_package_window.dart +++ b/mih_ui/lib/mih_package_components/mih_package_window.dart @@ -15,6 +15,7 @@ class MihPackageWindow extends StatefulWidget { final Color? foregroundColor; final bool? borderOn; final bool fullscreen; + final bool? scrollbarOn; const MihPackageWindow({ super.key, required this.fullscreen, @@ -23,6 +24,7 @@ class MihPackageWindow extends StatefulWidget { required this.onWindowTapClose, required this.windowBody, this.borderOn, + this.scrollbarOn, this.backgroundColor, this.foregroundColor, }); @@ -177,7 +179,13 @@ class _MihPackageWindowState extends State { getHeader(), const SizedBox(height: 5), Expanded( - child: SingleChildScrollView(child: widget.windowBody)), + child: widget.scrollbarOn != null || !widget.scrollbarOn! + ? widget.windowBody + : MihSingleChildScroll( + scrollbarOn: true, + child: widget.windowBody, + ), + ), ], ) : Column( From 6ad6b6ccbd1629d552cefb390c7809372895e4c9 Mon Sep 17 00:00:00 2001 From: yaso Date: Tue, 24 Feb 2026 15:41:55 +0200 Subject: [PATCH 29/31] Support linux version of MIH --- mih_ui/lib/mih_config/mih_env.dart | 12 ++----- mih_ui/lib/mih_config/mih_theme.dart | 6 ++++ .../mih_package_components/mih_package.dart | 5 +-- .../package_tools/mih_business_qr_code.dart | 19 +++++++++-- .../builder/build_loyalty_card_list.dart | 6 ++-- .../lib/mih_services/mih_alert_services.dart | 6 +++- .../lib/mih_services/mih_file_services.dart | 4 ++- .../mih_services/mih_location_services.dart | 8 +++++ mih_ui/pubspec.lock | 32 +++++++++++++++++++ mih_ui/pubspec.yaml | 1 + 10 files changed, 81 insertions(+), 18 deletions(-) diff --git a/mih_ui/lib/mih_config/mih_env.dart b/mih_ui/lib/mih_config/mih_env.dart index e9dcdd2f..9af57766 100644 --- a/mih_ui/lib/mih_config/mih_env.dart +++ b/mih_ui/lib/mih_config/mih_env.dart @@ -20,13 +20,13 @@ abstract class AppEnviroment { switch (env) { case Enviroment.dev: { - if (kIsWeb) { + if (kIsWeb || Platform.isIOS || Platform.isLinux) { //================= Web Dev Urls ================= baseAppUrl = "http://localhost:80"; baseApiUrl = "http://localhost:8080"; baseFileUrl = "http://localhost:9000"; baseAiUrl = "http://localhost:11434"; - bannerAdUnitId = 'ca-app-pub-3940256099942544/2435281174'; + bannerAdUnitId = 'ca-app-pub-3940256099942544/2435281174'; // IOS ID break; } else if (Platform.isAndroid) { //================= Android Dev Urls ================= @@ -35,14 +35,6 @@ abstract class AppEnviroment { baseFileUrl = "http://10.0.2.2:9000"; baseAiUrl = "http://10.0.2.2:11434"; bannerAdUnitId = 'ca-app-pub-3940256099942544/9214589741'; - } else { - //================= Web & iOS Dev Urls ================= - baseAppUrl = "http://localhost:80"; - baseApiUrl = "http://localhost:8080"; - baseFileUrl = "http://localhost:9000"; - baseAiUrl = "http://localhost:11434"; - bannerAdUnitId = 'ca-app-pub-3940256099942544/2435281174'; - break; } } case Enviroment.prod: diff --git a/mih_ui/lib/mih_config/mih_theme.dart b/mih_ui/lib/mih_config/mih_theme.dart index 02f1fa42..1e4870cc 100644 --- a/mih_ui/lib/mih_config/mih_theme.dart +++ b/mih_ui/lib/mih_config/mih_theme.dart @@ -98,6 +98,12 @@ class MihTheme { return "Android"; } else if (platform == TargetPlatform.iOS) { return "iOS"; + } else if (platform == TargetPlatform.linux) { + return "Linux"; + } else if (platform == TargetPlatform.macOS) { + return "macOS"; + } else if (platform == TargetPlatform.windows) { + return "Windows"; } } return "Other"; diff --git a/mih_ui/lib/mih_package_components/mih_package.dart b/mih_ui/lib/mih_package_components/mih_package.dart index e402d564..f387f5c7 100644 --- a/mih_ui/lib/mih_package_components/mih_package.dart +++ b/mih_ui/lib/mih_package_components/mih_package.dart @@ -1,7 +1,8 @@ +import 'dart:io'; + import 'package:flutter/services.dart'; import 'package:go_router/go_router.dart'; import 'package:ken_logger/ken_logger.dart'; -import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_scack_bar.dart'; import 'package:mzansi_innovation_hub/mih_packages/mih_home/components/mih_app_drawer.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_package_tools.dart'; @@ -100,7 +101,7 @@ class _MihPackageState extends State // _peakAnimation(); // }); // } - if (!MzansiInnovationHub.of(context)!.theme.kIsWeb) { + if (Platform.isAndroid || Platform.isIOS) { // Trigger the peak animation only AFTER the route transition is complete WidgetsBinding.instance.addPostFrameCallback((_) { final ModalRoute? currentRoute = ModalRoute.of(context); diff --git a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart index 4d6fd736..ab1142fa 100644 --- a/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart +++ b/mih_ui/lib/mih_packages/mzansi_profile/business_profile/package_tools/mih_business_qr_code.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:cached_network_image/cached_network_image.dart'; import 'package:file_picker/file_picker.dart'; import 'package:file_saver/file_saver.dart'; @@ -82,6 +84,19 @@ class _MihBusinessQrCodeState extends State { fileExtension: "png", mimeType: MimeType.png, ); + } else if (defaultTargetPlatform == TargetPlatform.linux || + defaultTargetPlatform == TargetPlatform.windows) { + // Use File Picker to get a save path on Desktop + String? outputFile = await FilePicker.platform.saveFile( + dialogTitle: 'Please select where to save your QR Code:', + fileName: filename, + ); + + if (outputFile != null) { + final file = File(outputFile); + await file.writeAsBytes(imageBytes); + KenLogger.success("Saved to $outputFile"); + } } else { await FileSaver.instance.saveAs( name: filename, @@ -95,14 +110,14 @@ class _MihBusinessQrCodeState extends State { Future downloadQrCode() async { if (_isUserSignedIn) { await screenshotController.capture().then((image) { - KenLogger.success("Image Captured: $image"); + // KenLogger.success("Image Captured: $image"); setState(() { businessQRImageFile = image; }); }).catchError((onError) { KenLogger.error(onError); }); - KenLogger.success("QR Code Image Captured : $businessQRImageFile"); + // KenLogger.success("QR Code Image Captured : $businessQRImageFile"); saveImage(businessQRImageFile!); } else { showSignInRequiredAlert(); diff --git a/mih_ui/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart b/mih_ui/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart index 9a7e84bf..be1cde25 100644 --- a/mih_ui/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart +++ b/mih_ui/lib/mih_packages/mzansi_wallet/builder/build_loyalty_card_list.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/foundation.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; import 'package:go_router/go_router.dart'; @@ -545,7 +547,7 @@ class _BuildLoyaltyCardListState extends State { ), ), SizedBox(height: 10), - MihBannerAd() + if (Platform.isAndroid || Platform.isIOS) MihBannerAd() // MihBannerAd(), ], ), @@ -572,7 +574,7 @@ class _BuildLoyaltyCardListState extends State { } Future setScreenBrightness(double newBrightness) async { - if (!kIsWeb) { + if (!kIsWeb && !Platform.isLinux) { bool canChange = await ScreenBrightness.instance.canChangeSystemBrightness; diff --git a/mih_ui/lib/mih_services/mih_alert_services.dart b/mih_ui/lib/mih_services/mih_alert_services.dart index fe01c2ce..c2e4e721 100644 --- a/mih_ui/lib/mih_services/mih_alert_services.dart +++ b/mih_ui/lib/mih_services/mih_alert_services.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:go_router/go_router.dart'; import 'package:mzansi_innovation_hub/main.dart'; @@ -134,7 +136,9 @@ class MihAlertServices { ), const SizedBox(height: 15), Text( - "To get the most out of MIH, we need your location. Please go to the site settings of the app and enable location services. Once you do that, we can start showing you relevant information based on your location.", + Platform.isLinux + ? "To get the most out of MIH, we need your location. Please go to your System Settings and enable location services. Once you do that, we can start showing you relevant information based on your location." + : "To get the most out of MIH, we need your location. Please go to the site settings of the app and enable location services. Once you do that, we can start showing you relevant information based on your location.", style: TextStyle( color: MihColors.getSecondaryColor( MzansiInnovationHub.of(context)!.theme.mode == diff --git a/mih_ui/lib/mih_services/mih_file_services.dart b/mih_ui/lib/mih_services/mih_file_services.dart index 76a15836..9dd0c8a8 100644 --- a/mih_ui/lib/mih_services/mih_file_services.dart +++ b/mih_ui/lib/mih_services/mih_file_services.dart @@ -55,10 +55,12 @@ class MihFileApi { // Navigator.of(context).pop(); // Always pop loading dialog } KenLogger.success("File URL: $fileUrl"); - if (AppEnviroment.getEnv() == "Dev" && isSkiaWeb) { + if (AppEnviroment.getEnv() == "Dev" && kIsWeb) { fileUrl = fileUrl.replaceAll("10.0.2.2", "127.0.0.1"); } else if (AppEnviroment.getEnv() == "Dev" && Platform.isIOS) { fileUrl = fileUrl.replaceAll("10.0.2.2", "127.0.0.1"); + } else if (AppEnviroment.getEnv() == "Dev" && Platform.isLinux) { + fileUrl = fileUrl.replaceAll("10.0.2.2", "127.0.0.1"); } KenLogger.success("File URL: $fileUrl"); return fileUrl; diff --git a/mih_ui/lib/mih_services/mih_location_services.dart b/mih_ui/lib/mih_services/mih_location_services.dart index a27c6e61..a18d745c 100644 --- a/mih_ui/lib/mih_services/mih_location_services.dart +++ b/mih_ui/lib/mih_services/mih_location_services.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:geolocator/geolocator.dart'; import 'package:mzansi_innovation_hub/mih_services/mih_alert_services.dart'; @@ -13,6 +15,12 @@ class MIHLocationAPI { ///if user has blocked permission (denied or denied forver), user will get error pop up. ///if user has granted permission (while in use), function will return Position object. Future getGPSPosition(BuildContext context) async { + bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); + if (!serviceEnabled && Platform.isLinux) { + // Direct the user to their System Settings + MihAlertServices().locationPermissionAlert(context); + return null; + } print("Before checkPermission"); // Debug LocationPermission permission = await Geolocator.checkPermission(); print("After checkPermission: $permission"); // Debug diff --git a/mih_ui/pubspec.lock b/mih_ui/pubspec.lock index 6c3cdb57..a253f2b4 100644 --- a/mih_ui/pubspec.lock +++ b/mih_ui/pubspec.lock @@ -369,6 +369,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.0" + dbus: + dependency: transitive + description: + name: dbus + sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 + url: "https://pub.dev" + source: hosted + version: "0.7.12" device_info_plus: dependency: transitive description: @@ -808,6 +816,14 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.0" + geoclue: + dependency: transitive + description: + name: geoclue + sha256: c2a998c77474fc57aa00c6baa2928e58f4b267649057a1c76738656e9dbd2a7f + url: "https://pub.dev" + source: hosted + version: "0.1.1" geolocator: dependency: "direct main" description: @@ -832,6 +848,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.13" + geolocator_linux: + dependency: "direct main" + description: + name: geolocator_linux + sha256: d64112a205931926f4363bb6bd48f14cb38e7326833041d170615586cd143797 + url: "https://pub.dev" + source: hosted + version: "0.2.4" geolocator_platform_interface: dependency: transitive description: @@ -904,6 +928,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + gsettings: + dependency: transitive + description: + name: gsettings + sha256: "1b0ce661f5436d2db1e51f3c4295a49849f03d304003a7ba177d01e3a858249c" + url: "https://pub.dev" + source: hosted + version: "0.2.8" html: dependency: transitive description: diff --git a/mih_ui/pubspec.yaml b/mih_ui/pubspec.yaml index f0b73b3e..e7d52726 100644 --- a/mih_ui/pubspec.yaml +++ b/mih_ui/pubspec.yaml @@ -29,6 +29,7 @@ dependencies: flutter_native_splash: ^2.4.6 printing: ^5.13.3 geolocator: ^14.0.1 + geolocator_linux: ^0.2.4 table_calendar: ^3.1.2 youtube_player_iframe: ^5.2.0 mobile_scanner: ^7.0.1 From 07d4ba4afa6283523eb7fcb550d7ff10d67494a4 Mon Sep 17 00:00:00 2001 From: yaso Date: Tue, 24 Feb 2026 16:30:06 +0200 Subject: [PATCH 30/31] Support linux version of MIHpt2 --- .../package_tools/package_tool_one.dart | 4 +- .../mih_package_tile.dart | 5 +- .../package_tools/currency_exchange_rate.dart | 8 ++- .../calculator/package_tools/tip_calc.dart | 8 ++- .../package_tools/mine_sweeper_game.dart | 5 +- .../mzansi_ai/package_tools/mih_ai_chat.dart | 50 +++++++++++---- .../mih_providers/mih_banner_ad_provider.dart | 62 ++++++++++--------- 7 files changed, 97 insertions(+), 45 deletions(-) diff --git a/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_one.dart b/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_one.dart index 47364ef8..95de0348 100644 --- a/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_one.dart +++ b/mih_ui/lib/mih_package_components/Example/package_tools/package_tool_one.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:country_code_picker/country_code_picker.dart'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; @@ -451,7 +453,7 @@ class _PackageToolOneState extends State { ), ], ), - MihBannerAd(), + if (Platform.isAndroid || Platform.isIOS) MihBannerAd(), const SizedBox(height: 10), Divider( color: MihColors.getSecondaryColor( diff --git a/mih_ui/lib/mih_package_components/mih_package_tile.dart b/mih_ui/lib/mih_package_components/mih_package_tile.dart index 5496841d..e5d25f35 100644 --- a/mih_ui/lib/mih_package_components/mih_package_tile.dart +++ b/mih_ui/lib/mih_package_components/mih_package_tile.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:app_settings/app_settings.dart'; import 'package:flutter/foundation.dart'; import 'package:local_auth/local_auth.dart'; @@ -155,7 +157,8 @@ class _MihPackageTileState extends State { Future authenticateUser() async { if (widget.authenticateUser != null && widget.authenticateUser! && - !kIsWeb) { + !kIsWeb && + !Platform.isLinux) { if (await isUserAuthenticated()) { widget.onTap(); } diff --git a/mih_ui/lib/mih_packages/calculator/package_tools/currency_exchange_rate.dart b/mih_ui/lib/mih_packages/calculator/package_tools/currency_exchange_rate.dart index c9ed4c87..794765ff 100644 --- a/mih_ui/lib/mih_packages/calculator/package_tools/currency_exchange_rate.dart +++ b/mih_ui/lib/mih_packages/calculator/package_tools/currency_exchange_rate.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:mzansi_innovation_hub/main.dart'; @@ -157,7 +159,11 @@ class _CurrencyExchangeRateState extends State { ), SizedBox(height: 10), Consumer(builder: (context, bannerAdDisplay, child) { - return MihBannerAd(); + if (Platform.isAndroid || Platform.isIOS) { + return MihBannerAd(); + } else { + return const SizedBox(height: 0); + } }), ], ), diff --git a/mih_ui/lib/mih_packages/calculator/package_tools/tip_calc.dart b/mih_ui/lib/mih_packages/calculator/package_tools/tip_calc.dart index a8d9a572..72ed50a6 100644 --- a/mih_ui/lib/mih_packages/calculator/package_tools/tip_calc.dart +++ b/mih_ui/lib/mih_packages/calculator/package_tools/tip_calc.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:mzansi_innovation_hub/main.dart'; import 'package:mzansi_innovation_hub/mih_package_components/mih_banner_ad.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart'; @@ -229,7 +231,11 @@ class _TipCalcState extends State { ), SizedBox(height: 10), Consumer(builder: (context, bannerAdDisplay, child) { - return MihBannerAd(); + if (Platform.isAndroid || Platform.isIOS) { + return MihBannerAd(); + } else { + return const SizedBox(height: 0); + } }), // if (splitBillController.text == "Yes") const Divider(), ], diff --git a/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart b/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart index 2fcdd04e..f400c98b 100644 --- a/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart +++ b/mih_ui/lib/mih_packages/mine_sweeper/package_tools/mine_sweeper_game.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:io'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_speed_dial/flutter_speed_dial.dart'; @@ -851,7 +852,9 @@ class _MineSweeperGameState extends State { ], ), ), - _timer != null ? MihBannerAd() : SizedBox(), + _timer != null && (Platform.isAndroid || Platform.isIOS) + ? MihBannerAd() + : SizedBox(), SizedBox(height: 15), ], ); diff --git a/mih_ui/lib/mih_packages/mzansi_ai/package_tools/mih_ai_chat.dart b/mih_ui/lib/mih_packages/mzansi_ai/package_tools/mih_ai_chat.dart index f4da1b6c..2ec0671e 100644 --- a/mih_ui/lib/mih_packages/mzansi_ai/package_tools/mih_ai_chat.dart +++ b/mih_ui/lib/mih_packages/mzansi_ai/package_tools/mih_ai_chat.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -112,15 +113,35 @@ class _MihAiChatState extends State with WidgetsBindingObserver { void speakLastMessage(MzansiAiProvider aiProvider) { final history = aiProvider.ollamaProvider.history; - if (history.isNotEmpty) { - final historyList = history.toList(); - for (int i = historyList.length - 1; i >= 0; i--) { - if (historyList[i].origin == MessageOrigin.llm && - historyList[i].text != null && - historyList[i].text!.isNotEmpty) { - _flutterTts.speak(historyList[i].text!); - return; - } + if (history.isEmpty) return; + + final historyList = history.toList(); + String? textToSpeak; + + // Find the last LLM message + for (int i = historyList.length - 1; i >= 0; i--) { + if (historyList[i].origin == MessageOrigin.llm && + historyList[i].text != null && + historyList[i].text!.isNotEmpty) { + textToSpeak = historyList[i].text!; + break; + } + } + + if (textToSpeak != null) { + if (Platform.isLinux) { + // Linux Workaround: Use Speech Dispatcher (standard on most distros) + // '-t female1' is optional for voice variety + Process.run('spd-say', [textToSpeak]); + + // Since spd-say doesn't have an easy "completion handler" via CLI, + // we manually toggle the UI state or just leave it off. + aiProvider.setTTSstate(true); + Future.delayed( + Duration(seconds: 5), () => aiProvider.setTTSstate(false)); + } else { + // Your existing mobile/web logic + _flutterTts.speak(textToSpeak); } } } @@ -183,11 +204,16 @@ class _MihAiChatState extends State with WidgetsBindingObserver { // } void stopTTS(MzansiAiProvider aiProvider) { - _flutterTts.stop(); + if (Platform.isLinux) { + Process.run('spd-say', ['-S']); // The -S flag stops current speech + } else { + _flutterTts.stop(); + } aiProvider.setTTSstate(false); } Future initTts(MzansiAiProvider aiProvider) async { + if (Platform.isLinux) return; try { await _flutterTts.setSpeechRate(!kIsWeb ? 0.55 : 1); // await _flutterTts.setLanguage("en-US"); @@ -258,7 +284,9 @@ class _MihAiChatState extends State with WidgetsBindingObserver { @override void dispose() { - _flutterTts.stop(); + if (!Platform.isLinux) { + _flutterTts.stop(); + } WidgetsBinding.instance.removeObserver(this); super.dispose(); } diff --git a/mih_ui/lib/mih_providers/mih_banner_ad_provider.dart b/mih_ui/lib/mih_providers/mih_banner_ad_provider.dart index 394bcbb4..e37594db 100644 --- a/mih_ui/lib/mih_providers/mih_banner_ad_provider.dart +++ b/mih_ui/lib/mih_providers/mih_banner_ad_provider.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:flutter/foundation.dart'; import 'package:google_mobile_ads/google_mobile_ads.dart'; import 'package:mzansi_innovation_hub/mih_config/mih_env.dart'; @@ -28,35 +30,37 @@ class MihBannerAdProvider extends ChangeNotifier { } void loadBannerAd() { - if (bannerAd != null) { - bannerAd!.dispose(); - bannerAd = null; - isBannerAdLoaded = false; + if (Platform.isAndroid || Platform.isIOS) { + if (bannerAd != null) { + bannerAd!.dispose(); + bannerAd = null; + isBannerAdLoaded = false; + } + bannerAd = BannerAd( + adUnitId: adUnitId, + request: const AdRequest(), + size: AdSize.banner, + listener: BannerAdListener( + onAdLoaded: (ad) { + debugPrint('$ad loaded.'); + isBannerAdLoaded = true; + notifyListeners(); + }, + onAdFailedToLoad: (ad, err) { + debugPrint('BannerAd failed to load: $err'); + errorMessage = + 'Failed to load ad- Message: ${err.message} Code :${err.code}'; + ad.dispose(); // Dispose the ad to free resources + isBannerAdLoaded = false; // ⬅️ Explicitly set to false + bannerAd = null; // ⬅️ Explicitly set to null + notifyListeners(); + }, + onAdOpened: (Ad ad) => debugPrint('$ad opened.'), + onAdClosed: (Ad ad) => debugPrint('$ad closed.'), + onAdImpression: (Ad ad) => debugPrint('$ad impression.'), + ), + ); + bannerAd!.load(); } - bannerAd = BannerAd( - adUnitId: adUnitId, - request: const AdRequest(), - size: AdSize.banner, - listener: BannerAdListener( - onAdLoaded: (ad) { - debugPrint('$ad loaded.'); - isBannerAdLoaded = true; - notifyListeners(); - }, - onAdFailedToLoad: (ad, err) { - debugPrint('BannerAd failed to load: $err'); - errorMessage = - 'Failed to load ad- Message: ${err.message} Code :${err.code}'; - ad.dispose(); // Dispose the ad to free resources - isBannerAdLoaded = false; // ⬅️ Explicitly set to false - bannerAd = null; // ⬅️ Explicitly set to null - notifyListeners(); - }, - onAdOpened: (Ad ad) => debugPrint('$ad opened.'), - onAdClosed: (Ad ad) => debugPrint('$ad closed.'), - onAdImpression: (Ad ad) => debugPrint('$ad impression.'), - ), - ); - bannerAd!.load(); } } From 1c0dd6d328cc5f7e0a1848350aa1712c117cfe27 Mon Sep 17 00:00:00 2001 From: Yasien Mac Mini Date: Wed, 25 Feb 2026 10:25:28 +0200 Subject: [PATCH 31/31] update build number to 130 --- mih_ui/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mih_ui/pubspec.yaml b/mih_ui/pubspec.yaml index e7d52726..2614956c 100644 --- a/mih_ui/pubspec.yaml +++ b/mih_ui/pubspec.yaml @@ -1,7 +1,7 @@ name: mzansi_innovation_hub description: "" publish_to: 'none' # Remove this line if you wish to publish to pub.dev -version: 1.2.6+129 +version: 1.2.6+130 # version: 1.1.1+97 #--- Updated version for upgrader package testing environment: