Mih File Structure enhancement

This commit is contained in:
2025-11-18 12:42:22 +02:00
parent f5c05d7431
commit b69a52a5a8
294 changed files with 2782 additions and 4473 deletions

View File

@@ -0,0 +1,19 @@
import 'package:flutter/foundation.dart';
class AboutMihProvider extends ChangeNotifier {
int toolIndex;
AboutMihProvider({
this.toolIndex = 0,
});
void reset() {
toolIndex = 0;
notifyListeners();
}
void setToolIndex(int index) {
toolIndex = index;
notifyListeners();
}
}

View File

@@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
import 'package:mzansi_innovation_hub/mih_objects/patient_access.dart';
class MihAccessControllsProvider extends ChangeNotifier {
int toolIndex;
List<PatientAccess>? accessList;
MihAccessControllsProvider({
this.toolIndex = 0,
});
void reset() {
toolIndex = 0;
accessList = null;
notifyListeners();
}
void setToolIndex(int index) {
toolIndex = index;
}
void setAccessList(List<PatientAccess> accesses) {
accessList = accesses;
notifyListeners();
}
void editAccessItem(PatientAccess updatedAccess) {
if (accessList == null) return;
int index = accessList!.indexWhere((access) =>
access.app_id == updatedAccess.app_id &&
access.business_id == updatedAccess.business_id);
if (index != -1) {
accessList![index] = updatedAccess;
notifyListeners();
}
}
}

View File

@@ -0,0 +1,19 @@
import 'package:flutter/foundation.dart';
class MihAuthenticationProvider extends ChangeNotifier {
int toolIndex;
MihAuthenticationProvider({
this.toolIndex = 0,
});
void reset() {
toolIndex = 0;
notifyListeners();
}
void setToolIndex(int index) {
toolIndex = index;
notifyListeners();
}
}

View File

@@ -0,0 +1,62 @@
import 'package:flutter/foundation.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_env.dart';
class MihBannerAdProvider extends ChangeNotifier {
BannerAd? bannerAd;
final adUnitId = AppEnviroment.bannerAdUnitId;
bool isBannerAdLoaded = false;
String errorMessage = '';
MihBannerAdProvider({
this.bannerAd,
this.isBannerAdLoaded = false,
this.errorMessage = '',
});
void reset() {
bannerAd = null;
isBannerAdLoaded = false;
errorMessage = "";
notifyListeners();
}
@override
void dispose() {
bannerAd?.dispose();
super.dispose();
}
void loadBannerAd() {
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();
}
}

View File

@@ -0,0 +1,27 @@
import 'package:flutter/foundation.dart';
class MihCalculatorProvider extends ChangeNotifier {
List<String> availableCurrencies;
int toolIndex;
MihCalculatorProvider({
this.availableCurrencies = const [],
this.toolIndex = 0,
});
void reset() {
availableCurrencies = [];
toolIndex = 0;
notifyListeners();
}
void setToolIndex(int index) {
toolIndex = index;
notifyListeners();
}
void setAvailableCurrencies({required List<String> currencies}) async {
availableCurrencies = currencies;
notifyListeners();
}
}

View File

@@ -0,0 +1,89 @@
import 'package:flutter/foundation.dart';
import 'package:ken_logger/ken_logger.dart';
import 'package:mzansi_innovation_hub/mih_objects/appointment.dart';
class MihCalendarProvider extends ChangeNotifier {
int toolIndex;
String selectedDay = DateTime.now().toString().split(" ")[0];
List<Appointment>? personalAppointments;
List<Appointment>? businessAppointments;
MihCalendarProvider({
this.toolIndex = 0,
});
void reset() {
toolIndex = 0;
personalAppointments = null;
businessAppointments = null;
notifyListeners();
}
void setToolIndex(int index) {
toolIndex = index;
notifyListeners();
}
void setSelectedDay(String day) {
selectedDay = day;
notifyListeners();
}
void resetSelectedDay() {
selectedDay = DateTime.now().toString().split(" ")[0];
notifyListeners();
}
void setPersonalAppointments({required List<Appointment> appointments}) {
personalAppointments = appointments;
notifyListeners();
}
void setBusinessAppointments({required List<Appointment> appointments}) {
businessAppointments = appointments;
notifyListeners();
}
void addPersonalAppointment({required Appointment newAppointment}) {
personalAppointments?.add(newAppointment);
notifyListeners();
}
void addBusinessAppointment({required Appointment newAppointment}) {
businessAppointments?.add(newAppointment);
notifyListeners();
}
void editPersonalAppointment({required Appointment updatedAppointment}) {
int index = personalAppointments?.indexWhere((appointment) =>
appointment.idappointments == updatedAppointment.idappointments) ??
-1;
KenLogger.success("Edit Patient Index: $index");
if (index != -1) {
personalAppointments?[index] = updatedAppointment;
notifyListeners();
}
}
void editBusinessAppointment({required Appointment updatedAppointment}) {
int index = businessAppointments?.indexWhere((appointment) =>
appointment.idappointments == updatedAppointment.idappointments) ??
-1;
if (index != -1) {
businessAppointments?[index] = updatedAppointment;
notifyListeners();
}
}
void deletePersonalAppointment({required int appointmentId}) {
personalAppointments?.removeWhere(
(appointment) => appointment.idappointments == appointmentId);
notifyListeners();
}
void deleteBusinessAppointment({required int appointmentId}) {
businessAppointments?.removeWhere(
(appointment) => appointment.idappointments == appointmentId);
notifyListeners();
}
}

View File

@@ -0,0 +1,28 @@
import 'package:flutter/material.dart';
class MihFileViewerProvider extends ChangeNotifier {
String filePath;
String fileLink;
int toolIndex;
MihFileViewerProvider({
this.filePath = '',
this.fileLink = '',
this.toolIndex = 0,
});
void setToolIndex(int index) {
toolIndex = index;
notifyListeners();
}
void setFilePath(String path) {
filePath = path;
notifyListeners();
}
void setFileLink(String name) {
fileLink = name;
notifyListeners();
}
}

View File

@@ -0,0 +1,81 @@
import 'package:flutter/widgets.dart';
import 'package:mzansi_innovation_hub/mih_objects/minesweeper_player_score.dart';
class MihMineSweeperProvider extends ChangeNotifier {
String difficulty;
int toolIndex;
int rowCount;
int columnCount;
int totalMines;
List<MinesweeperPlayerScore>? leaderboard;
List<MinesweeperPlayerScore>? myScoreboard;
List<ImageProvider<Object>?> leaderboardUserPictures = [];
MihMineSweeperProvider({
this.difficulty = "Easy",
this.toolIndex = 0,
this.rowCount = 10,
this.columnCount = 10,
this.totalMines = 15,
});
void reset() {
difficulty = "Easy";
toolIndex = 0;
rowCount = 10;
columnCount = 10;
totalMines = 15;
notifyListeners();
}
void setDifficulty(String difficulty) {
this.difficulty = difficulty;
notifyListeners();
}
void setToolIndex(int index) {
toolIndex = index;
notifyListeners();
}
void setRowCount(int rowCount) {
this.rowCount = rowCount;
notifyListeners();
}
void setCoulmnCount(int columnCount) {
this.columnCount = columnCount;
notifyListeners();
}
void setTotalMines(int totalMines) {
this.totalMines = totalMines;
notifyListeners();
}
void setLeaderboard({required List<MinesweeperPlayerScore>? leaderboard}) {
if (leaderboard == null) {
this.leaderboard = [];
} else {
this.leaderboard = leaderboard;
}
notifyListeners();
}
void setMyScoreboard({
required List<MinesweeperPlayerScore>? myScoreboard,
}) {
if (myScoreboard == null) {
this.myScoreboard = [];
} else {
this.myScoreboard = myScoreboard;
}
notifyListeners();
}
void setLeaderboardUserPictures(
{required List<ImageProvider<Object>?> leaderboardUserPictures}) {
this.leaderboardUserPictures = leaderboardUserPictures;
notifyListeners();
}
}

View File

@@ -0,0 +1,328 @@
import 'package:flutter/material.dart';
import 'package:flutter_ai_toolkit/flutter_ai_toolkit.dart';
import 'package:flutter_markdown_plus/flutter_markdown_plus.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_providers/ollama_provider.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_colors.dart';
import 'package:mzansi_innovation_hub/mih_config/mih_env.dart';
class MzansiAiProvider extends ChangeNotifier {
bool ttsOn;
int toolIndex;
String? startUpQuestion;
late OllamaProvider ollamaProvider;
MzansiAiProvider({
this.toolIndex = 0,
this.ttsOn = false,
}) {
ollamaProvider = OllamaProvider(
baseUrl: "${AppEnviroment.baseAiUrl}/api",
model: AppEnviroment.getEnv() == "Prod" ? 'gemma3n:e4b' : "gemma3:1b",
systemPrompt: "You are Mzansi AI, a helpful and friendly AI assistant running on the 'MIH App'.\n" +
"The MIH App was created by 'Mzansi Innovation Hub', a South African-based startup company." +
"Your primary purpose is to assist users by answering general questions and helping with creative writing tasks or any other task a user might have for you.\n" +
"Maintain a casual and friendly tone, but always remain professional.\n" +
"Strive for a balance between being empathetic and delivering factual information accurately.\n" +
"You may use lighthearted or playful language if the context is appropriate and enhances the user experience.\n" +
"You operate within the knowledge domain of the 'MIH App'.\n" +
"Here is a description of the MIH App and its features:\n" +
"MIH App Description: MIH is the first super app of Mzansi, designed to streamline both personal and business life. It's an all-in-one platform for managing professional profiles, teams, appointments, and quick calculations. \n" +
"Key Features:\n" +
"- Mzansi Profile: Central hub for managing personal and business information, including business team details." +
"- Mzansi Wallet: Digitally store loyalty cards.\n" +
"- Patient Manager (For Medical Practices): Seamless patient appointment scheduling and data management.\n" +
"- Mzansi AI: Your friendly AI assistant for quick answers and support (that's you!).\n" +
"- Mzansi Directory: A place to search and find out more about the people and businesses across Mzansi.\n" +
"- Calendar: Integrated calendar for managing personal and business appointments.\n" +
"- Calculator: Simple calculator with tip and forex calculation functionality.\n" +
"- MIH Minesweeper: The first game from MIH! It's the classic brain-teaser ready to entertain you no matter where you are.\n" +
"- MIH Access: Manage and view profile access security.\n" +
"**Core Rules and Guidelines:**\n" +
"- **Accuracy First:** Always prioritize providing correct information.\n" +
"- **Uncertainty Handling:** If you are unsure about an answer, politely respond with: 'Please bear with us as we are still learning and do not have all the answers.'\n" +
"- **Response Length:** Aim to keep responses under 250 words. If a more comprehensive answer is required, exceed this limit but offer to elaborate further (e.g., 'Would you like me to elaborate on this topic?').\n" +
"- **Language & Safety:** Never use offensive language or generate harmful content. If a user presses for information that is inappropriate or out of bounds, clearly state why you cannot provide it (e.g., 'I cannot assist with that request as it goes against my safety guidelines.').\n" +
"- **Out-of-Scope Questions:** - If a question is unclear, ask the user to rephrase or clarify it. - If a question is entirely out of your scope and you cannot provide a useful answer, admit you don't know. - If a user is unhappy with your response or needs further assistance beyond your capabilities, suggest they visit the 'Mzansi Innovation Hub Social Media Pages' for more direct support. Do not provide specific links, just refer to the pages generally.\n" +
"- **Target Audience:** Adapt your explanations to beginners and intermediate users, but be prepared for more complex questions from expert users. Ensure your language is clear and easy to understand.\n",
)..addListener(() {
notifyListeners(); // Forward OllamaProvider notifications
});
}
void reset() {
toolIndex = 0;
startUpQuestion = null;
notifyListeners();
}
void setToolIndex(int index) {
toolIndex = index;
notifyListeners();
}
void setTTSstate(bool ttsOn) {
this.ttsOn = ttsOn;
notifyListeners();
}
void setStartUpQuestion(String? question) {
startUpQuestion = question;
notifyListeners();
}
void clearStartUpQuestion() {
startUpQuestion = null;
}
MarkdownStyleSheet getLlmChatMarkdownStyle(BuildContext context) {
TextStyle body = TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 16,
fontWeight: FontWeight.w400,
);
TextStyle heading1 = TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 24,
fontWeight: FontWeight.w400,
);
TextStyle heading2 = TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 20,
fontWeight: FontWeight.w400,
);
TextStyle code = TextStyle(
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
fontSize: 16,
fontWeight: FontWeight.w400,
);
BoxDecoration codeBlock = BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10),
),
color: MihColors.getHighlightColor(
MzansiInnovationHub.of(context)!.theme.mode != "Dark"),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(76),
blurRadius: 8,
offset: Offset(2, 2),
),
],
);
return MarkdownStyleSheet(
a: body,
blockquote: body,
checkbox: body,
del: body,
em: body.copyWith(fontStyle: FontStyle.italic),
h1: heading1,
h2: heading2,
h3: body.copyWith(fontWeight: FontWeight.bold),
h4: body,
h5: body,
h6: body,
listBullet: body,
img: body,
strong: body.copyWith(fontWeight: FontWeight.bold),
p: body,
tableBody: body,
tableHead: body,
code: code,
codeblockDecoration: codeBlock,
);
}
LlmChatViewStyle? getChatStyle(BuildContext context) {
return LlmChatViewStyle(
backgroundColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
progressIndicatorColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
menuColor: Colors.black,
// MihColors.getGreenColor(
// MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
disabledButtonStyle: ActionButtonStyle(
icon: MihIcons.mzansiAi,
iconColor: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
iconDecoration: BoxDecoration(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
borderRadius: BorderRadius.circular(25),
),
),
recordButtonStyle: ActionButtonStyle(
iconColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
iconDecoration: BoxDecoration(
color: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
borderRadius: BorderRadius.circular(25),
),
textStyle: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
submitButtonStyle: ActionButtonStyle(
icon: Icons.send,
iconColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
iconDecoration: BoxDecoration(
color: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
borderRadius: BorderRadius.circular(25),
),
textStyle: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
stopButtonStyle: ActionButtonStyle(
iconColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
iconDecoration: BoxDecoration(
color: MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
borderRadius: BorderRadius.circular(25),
),
textStyle: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
actionButtonBarDecoration: BoxDecoration(
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
borderRadius: BorderRadius.circular(25),
),
// Mzansi AI Chat Style
llmMessageStyle: LlmMessageStyle(
icon: MihIcons.mzansiAi,
iconColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
iconDecoration: BoxDecoration(
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
borderRadius: BorderRadius.circular(25),
),
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topRight: Radius.circular(25),
bottomLeft: Radius.circular(25),
bottomRight: Radius.circular(25),
),
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(76),
blurRadius: 8,
offset: Offset(2, 2),
),
],
),
markdownStyle: getLlmChatMarkdownStyle(context),
),
// User Chat Style
userMessageStyle: UserMessageStyle(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25),
bottomLeft: Radius.circular(25),
bottomRight: Radius.circular(25),
),
color: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(76),
blurRadius: 8,
offset: Offset(2, 2),
),
],
),
textStyle: TextStyle(
fontSize: 16,
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
// User Input Style
chatInputStyle: ChatInputStyle(
backgroundColor: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
decoration: BoxDecoration(
color: MihColors.getSecondaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
borderRadius: BorderRadius.circular(25),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(76),
blurRadius: 8,
offset: Offset(2, 2),
),
],
),
hintStyle: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
hintText: "Ask Mzansi AI...",
),
// Suggestions Style
suggestionStyle: SuggestionStyle(
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(25),
bottomLeft: Radius.circular(25),
bottomRight: Radius.circular(25),
),
color: MihColors.getGreenColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(76),
blurRadius: 8,
offset: Offset(2, 2),
),
],
),
textStyle: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
copyButtonStyle: ActionButtonStyle(
iconColor: MihColors.getSecondaryInvertedColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
editButtonStyle: ActionButtonStyle(
iconColor: MihColors.getSecondaryInvertedColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
cancelButtonStyle: ActionButtonStyle(
iconDecoration: BoxDecoration(
color: MihColors.getRedColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
borderRadius: BorderRadius.circular(25),
),
iconColor: MihColors.getSecondaryInvertedColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
textStyle: TextStyle(
color: MihColors.getPrimaryColor(
MzansiInnovationHub.of(context)!.theme.mode == "Dark"),
),
),
);
}
}

View File

@@ -0,0 +1,104 @@
import 'package:flutter/material.dart';
import 'package:geolocator/geolocator.dart';
import 'package:mzansi_innovation_hub/mih_objects/app_user.dart';
import 'package:mzansi_innovation_hub/mih_objects/bookmarked_business.dart';
import 'package:mzansi_innovation_hub/mih_objects/business.dart';
class MzansiDirectoryProvider extends ChangeNotifier {
int toolIndex;
Position? userPosition;
String userLocation;
bool personalSearch;
List<BookmarkedBusiness> bookmarkedBusinesses = [];
List<Business>? favouriteBusinessesList;
List<Business>? searchedBusinesses;
Business? selectedBusiness;
List<AppUser>? searchedUsers;
AppUser? selectedUser;
String searchTerm;
String businessTypeFilter;
MzansiDirectoryProvider({
this.toolIndex = 0,
this.personalSearch = true,
this.userLocation = "Unknown Location",
this.searchTerm = "",
this.businessTypeFilter = "",
});
void reset() {
toolIndex = 0;
userPosition = null;
userLocation = "Unknown Location";
personalSearch = true;
bookmarkedBusinesses = [];
searchedBusinesses = null;
selectedBusiness = null;
searchedUsers = null;
selectedUser = null;
searchTerm = "";
businessTypeFilter = "";
notifyListeners();
}
void setToolIndex(int index) {
toolIndex = index;
notifyListeners();
}
void setUserPosition(Position? position) {
userPosition = position;
if (position == null) {
userLocation = "Unknown Location";
} else {
userLocation = "${position.latitude}, ${position.longitude}";
}
notifyListeners();
}
void setPersonalSearch(bool personal) {
personalSearch = personal;
notifyListeners();
}
void setBookmarkedeBusinesses(
{required List<BookmarkedBusiness> businesses}) {
bookmarkedBusinesses = businesses;
notifyListeners();
}
void setFavouriteBusinesses({required List<Business> businesses}) {
favouriteBusinessesList = businesses;
notifyListeners();
}
void setSearchedBusinesses({required List<Business> searchedBusinesses}) {
this.searchedBusinesses = searchedBusinesses;
notifyListeners();
}
void setSelectedBusiness({required Business business}) {
selectedBusiness = business;
notifyListeners();
}
void setSearchedUsers({required List<AppUser> searchedUsers}) {
this.searchedUsers = searchedUsers;
notifyListeners();
}
void setSelectedUser({required AppUser user}) {
selectedUser = user;
notifyListeners();
}
void setSearchTerm({required String searchTerm}) {
this.searchTerm = searchTerm;
notifyListeners();
}
void setBusinessTypeFilter({required String businessTypeFilter}) {
this.businessTypeFilter = businessTypeFilter;
notifyListeners();
}
}

View File

@@ -0,0 +1,141 @@
import 'package:flutter/material.dart';
import 'package:mzansi_innovation_hub/mih_objects/app_user.dart';
import 'package:mzansi_innovation_hub/mih_objects/business.dart';
import 'package:mzansi_innovation_hub/mih_objects/business_employee.dart';
import 'package:mzansi_innovation_hub/mih_objects/business_user.dart';
import 'package:mzansi_innovation_hub/mih_objects/user_consent.dart';
class MzansiProfileProvider extends ChangeNotifier {
bool personalHome;
int personalIndex;
int businessIndex;
AppUser? user;
String? userProfilePicUrl;
ImageProvider<Object>? userProfilePicture;
Business? business;
String? businessProfilePicUrl;
ImageProvider<Object>? businessProfilePicture;
BusinessUser? businessUser;
String? businessUserSignatureUrl;
ImageProvider<Object>? businessUserSignature;
UserConsent? userConsent;
List<BusinessEmployee>? employeeList;
List<AppUser> userSearchResults = [];
MzansiProfileProvider({
this.personalHome = true,
this.personalIndex = 0,
this.businessIndex = 0,
});
void reset() {
personalHome = true;
personalIndex = 0;
businessIndex = 0;
user = null;
userProfilePicUrl = null;
userProfilePicture = null;
business = null;
businessProfilePicUrl = null;
businessProfilePicture = null;
businessUser = null;
businessUserSignatureUrl = null;
businessUserSignature = null;
userConsent = null;
notifyListeners();
}
void setPersonalHome(bool isPersonalHome) {
personalHome = isPersonalHome;
notifyListeners();
}
void setPersonalIndex(int index) {
personalIndex = index;
notifyListeners();
}
void setBusinessIndex(int index) {
businessIndex = index;
notifyListeners();
}
void setUser({
required AppUser newUser,
}) {
user = newUser;
notifyListeners();
}
void setUserProfilePicUrl(String url) {
userProfilePicUrl = url;
userProfilePicture = url.isNotEmpty ? NetworkImage(url) : null;
notifyListeners();
}
void setBusiness({
Business? newBusiness,
}) {
business = newBusiness;
notifyListeners();
}
void setBusinessProfilePicUrl(String url) {
businessProfilePicUrl = url;
businessProfilePicture = url.isNotEmpty ? NetworkImage(url) : null;
notifyListeners();
}
void setBusinessUser({required BusinessUser newBusinessUser}) {
businessUser = newBusinessUser;
notifyListeners();
}
void setBusinessUserSignatureUrl(String url) {
businessUserSignatureUrl = url;
businessUserSignature = url.isNotEmpty ? NetworkImage(url) : null;
notifyListeners();
}
void setUserConsent(UserConsent? newUserConsent) {
userConsent = newUserConsent;
notifyListeners();
}
void setEmployeeList({required List<BusinessEmployee> employeeList}) {
this.employeeList = employeeList;
notifyListeners();
}
void addLoyaltyCard({required BusinessEmployee newEmployee}) {
employeeList!.add(newEmployee);
notifyListeners();
}
void updateEmplyeeDetails({required BusinessEmployee updatedEmployee}) {
int index = employeeList!.indexWhere((employee) =>
employee.business_id == updatedEmployee.business_id &&
employee.app_id == updatedEmployee.app_id);
if (index != -1) {
employeeList![index] = updatedEmployee;
notifyListeners();
}
}
void deleteEmplyee({required BusinessEmployee deletedEmployee}) {
employeeList!.removeWhere((employee) =>
employee.business_id == deletedEmployee.business_id &&
employee.app_id == deletedEmployee.app_id);
notifyListeners();
}
void addEmployee({required BusinessEmployee newEmployee}) {
employeeList!.add(newEmployee);
notifyListeners();
}
void setUserearchResults({required List<AppUser> userSearchResults}) {
this.userSearchResults = userSearchResults;
notifyListeners();
}
}

View File

@@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
import 'package:mzansi_innovation_hub/mih_objects/loyalty_card.dart';
class MzansiWalletProvider extends ChangeNotifier {
List<MIHLoyaltyCard> loyaltyCards;
List<MIHLoyaltyCard> favouriteCards;
int toolIndex;
MzansiWalletProvider({
this.loyaltyCards = const [],
this.favouriteCards = const [],
this.toolIndex = 0,
});
void reset() {
toolIndex = 0;
loyaltyCards = [];
favouriteCards = [];
}
void setToolIndex(int index) {
toolIndex = index;
notifyListeners();
}
void setLoyaltyCards({required List<MIHLoyaltyCard> cards}) async {
loyaltyCards = cards;
notifyListeners();
}
void setFavouriteCards({required List<MIHLoyaltyCard> cards}) async {
favouriteCards = cards;
notifyListeners();
}
void deleteLoyaltyCard({required int cardId}) {
loyaltyCards.removeWhere((card) => card.idloyalty_cards == cardId);
notifyListeners();
}
void editLoyaltyCard({required MIHLoyaltyCard updatedCard}) {
int index = loyaltyCards.indexWhere(
(card) => card.idloyalty_cards == updatedCard.idloyalty_cards);
if (index != -1) {
loyaltyCards[index] = updatedCard;
notifyListeners();
}
}
}

View File

@@ -0,0 +1,141 @@
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter_ai_toolkit/flutter_ai_toolkit.dart';
import 'package:ken_logger/ken_logger.dart';
import 'package:ollama_dart/ollama_dart.dart';
class OllamaProvider extends LlmProvider with ChangeNotifier {
OllamaProvider({
String? baseUrl,
Map<String, String>? headers,
Map<String, String>? queryParams,
required String model,
String? systemPrompt,
}) : _client = OllamaClient(
baseUrl: baseUrl,
headers: headers,
queryParams: queryParams,
),
_model = model,
_systemPrompt = systemPrompt,
_history = [];
final OllamaClient _client;
final String _model;
final List<ChatMessage> _history;
final String? _systemPrompt;
@override
Stream<String> generateStream(
String prompt, {
Iterable<Attachment> attachments = const [],
}) async* {
final messages = _mapToOllamaMessages([
ChatMessage.user(prompt, attachments),
]);
yield* _generateStream(messages);
}
@override
Stream<String> sendMessageStream(
String prompt, {
Iterable<Attachment> attachments = const [],
}) async* {
KenLogger.success("sendMessageStream called with: $prompt");
final userMessage = ChatMessage.user(prompt, attachments);
final llmMessage = ChatMessage.llm();
_history.addAll([userMessage, llmMessage]);
notifyListeners();
KenLogger.success("History after adding messages: ${_history.length}");
final messages = _mapToOllamaMessages(_history);
final stream = _generateStream(messages);
yield* stream.map((chunk) {
llmMessage.append(chunk);
notifyListeners();
return chunk;
});
KenLogger.success("Stream completed for: $prompt");
notifyListeners();
}
@override
Iterable<ChatMessage> get history => _history;
void resetChat() {
_history.clear();
notifyListeners();
}
@override
set history(Iterable<ChatMessage> history) {
_history.clear();
_history.addAll(history);
notifyListeners();
}
Stream<String> _generateStream(List<Message> messages) async* {
final allMessages = <Message>[];
if (_systemPrompt != null && _systemPrompt.isNotEmpty) {
allMessages.add(Message(
role: MessageRole.system,
content: _systemPrompt,
));
}
allMessages.addAll(messages);
final stream = _client.generateChatCompletionStream(
request: GenerateChatCompletionRequest(
model: _model,
messages: allMessages,
),
);
// final stream = _client.generateChatCompletionStream(
// request: GenerateChatCompletionRequest(
// model: _model,
// messages: messages,
// ),
// );
yield* stream.map((res) => res.message.content);
}
List<Message> _mapToOllamaMessages(List<ChatMessage> messages) {
return messages.map((message) {
switch (message.origin) {
case MessageOrigin.user:
if (message.attachments.isEmpty) {
return Message(
role: MessageRole.user,
content: message.text ?? '',
);
}
return Message(
role: MessageRole.user,
content: message.text ?? '',
images: [
for (final attachment in message.attachments)
if (attachment is ImageFileAttachment)
base64Encode(attachment.bytes)
else
throw LlmFailureException(
'Unsupported attachment type: $attachment',
),
],
);
case MessageOrigin.llm:
return Message(
role: MessageRole.assistant,
content: message.text ?? '',
);
}
}).toList(growable: false);
}
@override
void dispose() {
_client.endSession();
super.dispose();
}
}

View File

@@ -0,0 +1,99 @@
import 'package:flutter/material.dart';
import 'package:mzansi_innovation_hub/mih_objects/claim_statement_file.dart';
import 'package:mzansi_innovation_hub/mih_objects/files.dart';
import 'package:mzansi_innovation_hub/mih_objects/notes.dart';
import 'package:mzansi_innovation_hub/mih_objects/patient_access.dart';
import 'package:mzansi_innovation_hub/mih_objects/patients.dart';
class PatientManagerProvider extends ChangeNotifier {
int patientProfileIndex;
int patientManagerIndex;
int fileViewerIndex;
bool personalMode;
List<PatientAccess>? myPaitentList;
Patient? selectedPatient;
String? selectedPatientProfilePictureUrl;
ImageProvider<Object>? selectedPatientProfilePicture;
bool hidePatientDetails;
List<Note>? consultationNotes;
List<PFile>? patientDocuments;
List<ClaimStatementFile>? patientClaimsDocuments;
List<Patient> patientSearchResults = [];
PatientManagerProvider({
this.patientProfileIndex = 0,
this.patientManagerIndex = 0,
this.fileViewerIndex = 0,
this.personalMode = true,
this.hidePatientDetails = true,
});
void reset() {
patientProfileIndex = 0;
patientManagerIndex = 0;
personalMode = true;
selectedPatient = null;
}
void setPatientProfileIndex(int index) {
patientProfileIndex = index;
notifyListeners();
}
void setPatientManagerIndex(int index) {
patientManagerIndex = index;
notifyListeners();
}
void setFileViewerIndex(int index) {
patientProfileIndex = index;
notifyListeners();
}
void setPersonalMode(bool personalMode) {
this.personalMode = personalMode;
notifyListeners();
}
void setSelectedPatient({required Patient? selectedPatient}) {
this.selectedPatient = selectedPatient;
notifyListeners();
}
void setSelectedPatientProfilePicUrl(String url) {
selectedPatientProfilePictureUrl = url;
selectedPatientProfilePicture = url.isNotEmpty ? NetworkImage(url) : null;
notifyListeners();
}
void setHidePatientDetails(bool hidePatientDetails) {
this.hidePatientDetails = hidePatientDetails;
notifyListeners();
}
void setMyPatientList({required List<PatientAccess>? myPaitentList}) {
this.myPaitentList = myPaitentList ?? [];
notifyListeners();
}
void setConsultationNotes({required List<Note>? consultationNotes}) {
this.consultationNotes = consultationNotes ?? [];
notifyListeners();
}
void setPatientDocuments({required List<PFile>? patientDocuments}) {
this.patientDocuments = patientDocuments ?? [];
notifyListeners();
}
void setClaimsDocuments(
{required List<ClaimStatementFile>? patientClaimsDocuments}) {
this.patientClaimsDocuments = patientClaimsDocuments ?? [];
notifyListeners();
}
void setPatientSearchResults({required List<Patient> patientSearchResults}) {
this.patientSearchResults = patientSearchResults;
notifyListeners();
}
}