Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions assets/lang/de.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"sendButtonKey": "schicken",
"AgentUrlKey": "Agent Url",
"AgentNotFoundKey": "Keine Agenten gefunden"
}
5 changes: 5 additions & 0 deletions assets/lang/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"sendButtonKey": "Send",
"AgentUrlKey": "Agent Url",
"AgentNotFoundKey": "No Agents found"
}
5 changes: 5 additions & 0 deletions assets/lang/fr.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"sendButtonKey": "envoyer",
"AgentUrlKey": "URL de l'agent",
"AgentNotFoundKey": "Aucun agent trouvé"
}
3 changes: 2 additions & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ late SharedPreferences preferences;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
preferences = await SharedPreferences.getInstance();
runApp(const ProviderScope(child: MessagingApp()));
String? languageCode = preferences.getString('selectedLanguage') ?? 'en'; //default is english
runApp(ProviderScope(child: MessagingApp(languageCode: languageCode)));
}

@riverpod
Expand Down
15 changes: 14 additions & 1 deletion lib/src/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,26 @@
import 'package:flutter/material.dart';
import 'package:arc_view/src/routes.dart';
import 'package:arc_view/src/themes.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'core/app_localization.dart';

class MessagingApp extends StatelessWidget {
const MessagingApp({super.key});
final String languageCode;
late Locale? _locale;

MessagingApp({required this.languageCode, super.key});

@override
Widget build(BuildContext context) {
_locale = Locale(languageCode);
return MaterialApp.router(
locale: _locale,
supportedLocales: const[Locale('en'), Locale('de'), Locale('fr')],
localizationsDelegates: const [
AppLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
title: 'Messaging App',
routerConfig: appRoutes,
debugShowCheckedModeBanner: false,
Expand Down
9 changes: 6 additions & 3 deletions lib/src/chat/address_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import 'package:arc_view/src/core/extensions.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../core/app_localization.dart';

class AddressBar extends StatefulWidget {
const AddressBar({super.key});

Expand All @@ -31,9 +33,10 @@ class _AddressBarState extends State<AddressBar> {
TextField(
controller: TextEditingController(
text: agentClient.agentUrl.url.toString()),
decoration: const InputDecoration(
border: OutlineInputBorder(),
labelText: 'Agent Url',
decoration: InputDecoration(
border: const OutlineInputBorder(),
labelText: AppLocalizations.of(context)
.translate('AgentUrlKey'),
isDense: true, // Added this
),
onChanged: (value) {
Expand Down
10 changes: 7 additions & 3 deletions lib/src/chat/chat_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@ import 'package:arc_view/src/chat/address_bar.dart';
import 'package:arc_view/src/chat/chat_field.dart';
import 'package:arc_view/src/chat/chat_list.dart';
import 'package:arc_view/src/chat/toolbar/tool_bar.dart';
import 'package:arc_view/src/prompts/prompt_history_notifier.dart';
import 'package:arc_view/src/prompts/prompt_list.dart';
import 'package:arc_view/src/conversation/conversation_notifier.dart';
import 'package:arc_view/src/core/extensions.dart';
import 'package:arc_view/src/layout/adaptive_scaffold.dart';
import 'package:arc_view/src/prompts/prompt_history_notifier.dart';
import 'package:arc_view/src/prompts/prompt_list.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../core/app_localization.dart';

class ChatScreen extends StatefulWidget {
const ChatScreen({super.key});

Expand Down Expand Up @@ -99,7 +101,9 @@ class _ChatScreenState extends State<ChatScreen> {
showPromptList(context);
});

_sendButton(WidgetRef ref) => 'Send'.onButtonPressed(() => _send(ref));
_sendButton(WidgetRef ref) => AppLocalizations.of(context)
.translate('sendButtonKey')
.onButtonPressed(() => _send(ref));

_send(WidgetRef ref) {
if (_textController.text.isEmpty) return;
Expand Down
5 changes: 4 additions & 1 deletion lib/src/chat/toolbar/agent_tabs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import 'package:arc_view/src/core/extensions.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

import '../../core/app_localization.dart';

class AgentTabs extends ConsumerWidget {
const AgentTabs({super.key});

Expand All @@ -24,7 +26,8 @@ class AgentTabs extends ConsumerWidget {
color: context.colorScheme.onSurface,
),
if (agents == null || agents.names.isEmpty)
'No Agents found'
AppLocalizations.of(context)
.translate('AgentNotFoundKey')
.style(color: context.colorScheme.onSurface.withOpacity(0.5))
.pad(4, 8, 4, 8),
if (agents != null)
Expand Down
134 changes: 134 additions & 0 deletions lib/src/conversation/language_preference.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:shared_preferences/shared_preferences.dart';

class LanguagePreferenceScreen extends StatefulWidget {
const LanguagePreferenceScreen({super.key});

@override
_LanguageSelectionScreenState createState() =>
_LanguageSelectionScreenState();
}

class _LanguageSelectionScreenState extends State<LanguagePreferenceScreen> {
String selectedLanguageName = 'English (UK)';
String selectedLanguage = 'en';

final List<Map<String, String>> languages = [
{"name": "English (UK)", "flagCode": "gb", "code": 'en'},
{"name": "French", "flagCode": "fr", "code": 'fr'},
{"name": "German", "flagCode": "de", "code": 'de'},
{"name": "Spanish", "flagCode": "es", "code": 'es'}
];

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Languages'),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
},
),
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'Selected Language',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
Card(
margin: const EdgeInsets.symmetric(horizontal: 16.0),
child: ListTile(
leading: Image.asset(
'icons/flags/png/${languages.firstWhere((lang) => lang["name"] == selectedLanguageName)["flagCode"]}.png',
package: 'country_icons',
width: 30,
height: 30,
),
title: Text(selectedLanguageName),
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'All Languages',
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
Expanded(
child: ListView.builder(
itemCount: languages.length,
itemBuilder: (context, index) {
return Card(
margin: const EdgeInsets.symmetric(
horizontal: 16.0, vertical: 4.0),
child: ListTile(
leading: Image.asset(
'icons/flags/png/${languages[index]["flagCode"]}.png',
package: 'country_icons',
width: 30,
height: 30,
),
title: Text(languages[index]["name"]!),
trailing: Radio<String>(
value: languages[index]["name"]!,
groupValue: selectedLanguageName,
onChanged: (String? value) {
setState(() {
selectedLanguageName = value!;
selectedLanguage = languages[index]["code"]!;
});
},
),
),
);
},
),
),
Padding(
padding: const EdgeInsets.all(16.0),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(
vertical: 16.0, horizontal: 32.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
onPressed: () {
// Handle save settings action
_selectLanguage(context,selectedLanguage);
context.go("/chat");
},
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text('Save Settings'),
SizedBox(width: 8),
Icon(Icons.check),
],
),
),
),
],
),
);
}

void _selectLanguage(BuildContext context, String languageCode) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
await prefs.setString('selectedLanguage', languageCode);
}
}
55 changes: 55 additions & 0 deletions lib/src/core/app_localization.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

class AppLocalizations {
final Locale locale;

AppLocalizations(this.locale);

static AppLocalizations of(BuildContext context) {
return Localizations.of<AppLocalizations>(context, AppLocalizations)!;
}

static const LocalizationsDelegate<AppLocalizations> delegate =
_AppLocalizationsDelegate();

Map<String, String> _localizedStrings = {};

Future<bool> load() async {
String jsonString =
await rootBundle.loadString('assets/lang/${locale.languageCode}.json');
Map<String, dynamic> jsonMap = json.decode(jsonString);

_localizedStrings =
jsonMap.map((key, value) => MapEntry(key, value.toString()));
return true;
}

String translate(String key) {
return _localizedStrings[key] ?? key;
}
}

class _AppLocalizationsDelegate
extends LocalizationsDelegate<AppLocalizations> {
const _AppLocalizationsDelegate();

@override
bool isSupported(Locale locale) {
//to-do this could be configurable
return ['en', 'de','fr'].contains(locale.languageCode);
}

@override
Future<AppLocalizations> load(Locale locale) async {
AppLocalizations localizations = AppLocalizations(locale);
await localizations.load();
return localizations;
}

@override
bool shouldReload(covariant LocalizationsDelegate<AppLocalizations> old) =>
false;
}
13 changes: 9 additions & 4 deletions lib/src/routes.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,16 @@ import 'package:arc_view/src/layout/main_layout.dart';
import 'package:arc_view/src/settings/settings_screen.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:arc_view/src/conversation/language_preference.dart';

final GlobalKey<NavigatorState> _rootNavigatorKey =
GlobalKey<NavigatorState>(debugLabel: 'root');
GlobalKey<NavigatorState>(debugLabel: 'root');
final GlobalKey<NavigatorState> _mainNavigatorKey =
GlobalKey<NavigatorState>(debugLabel: 'mainNav');
GlobalKey<NavigatorState>(debugLabel: 'mainNav');

/// Main Routing
final appRoutes =
GoRouter(initialLocation: '/', navigatorKey: _rootNavigatorKey, routes: [
GoRouter(initialLocation: '/', navigatorKey: _rootNavigatorKey, routes: [
ShellRoute(
navigatorKey: _mainNavigatorKey,
builder: (context, state, child) {
Expand All @@ -26,7 +27,11 @@ final appRoutes =
routes: [
GoRoute(
path: '/',
builder: (context, state) => const ChatScreen(),
builder: (context, state) => const LanguagePreferenceScreen(),
),
GoRoute(
path: '/chat',
builder: (context, state) => const ChatScreen(),
),
GoRoute(
path: '/settings',
Expand Down
4 changes: 0 additions & 4 deletions linux/flutter/generated_plugin_registrant.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
// SPDX-FileCopyrightText: 2024 Deutsche Telekom AG
//
// SPDX-License-Identifier: Apache-2.0

//
// Generated file. Do not edit.
//
Expand Down
13 changes: 13 additions & 0 deletions pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.1.1"
country_icons:
dependency: "direct main"
description:
name: country_icons
sha256: "836435012b42c7dcc6d585d1420ce2310d70396569ef70cf5d74c740919f7320"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
cross_file:
dependency: transitive
description:
Expand Down Expand Up @@ -379,6 +387,11 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.0"
flutter_localizations:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_riverpod:
dependency: "direct main"
description:
Expand Down
Loading