Added Settings Option to show only profiles from the same country.
parent
d567956d90
commit
77ffb5ffcf
|
@ -69,4 +69,5 @@ class Constants {
|
|||
static const String pathLanguagesJson = 'lib/assets/languages.json';
|
||||
|
||||
static const String prefKeyThemeDarkMode = 'theme_dark_mode';
|
||||
static const String prefKeySameCountry = 'match_same_country';
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import 'pages/liked_users_page.dart';
|
|||
import 'pages/user_matching_page.dart';
|
||||
import 'pages/user_profile_page.dart';
|
||||
import 'services/swipe_stream_service.dart';
|
||||
import 'settings/settings_provider.dart';
|
||||
|
||||
void main() async {
|
||||
// Firebase stuff
|
||||
|
@ -23,6 +24,7 @@ void main() async {
|
|||
// Init SharedPreferences
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final isDarkMode = prefs.getBool(Constants.prefKeyThemeDarkMode) ?? false;
|
||||
final onlySameCountry = prefs.getBool(Constants.prefKeySameCountry) ?? false;
|
||||
|
||||
final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
|
||||
FlutterLocalNotificationsPlugin();
|
||||
|
@ -70,6 +72,10 @@ void main() async {
|
|||
create: (context) => ThemeProvider(initialIsDarkMode: isDarkMode)),
|
||||
Provider<FlutterLocalNotificationsPlugin>.value(
|
||||
value: flutterLocalNotificationsPlugin),
|
||||
ChangeNotifierProvider(
|
||||
create: (context) =>
|
||||
SettingsProvider(showSameCountry: onlySameCountry),
|
||||
),
|
||||
],
|
||||
child: const MyApp(),
|
||||
),
|
||||
|
|
|
@ -3,6 +3,8 @@ import 'package:flutter/cupertino.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../settings/settings_provider.dart';
|
||||
|
||||
class SettingsPage extends StatelessWidget {
|
||||
const SettingsPage({super.key});
|
||||
|
||||
|
@ -13,27 +15,61 @@ class SettingsPage extends StatelessWidget {
|
|||
appBar: AppBar(
|
||||
title: const Text("Settings"),
|
||||
),
|
||||
body: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
margin: const EdgeInsets.all(25),
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
body: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
// dark mode switch
|
||||
const Text("Dark Mode"),
|
||||
Consumer<ThemeProvider>(
|
||||
builder: (context, themeProvider, child) {
|
||||
return CupertinoSwitch(
|
||||
value: themeProvider.isDarkMode,
|
||||
onChanged: (value) {
|
||||
themeProvider.toggleTheme();
|
||||
},
|
||||
);
|
||||
},
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
margin: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
// dark mode switch
|
||||
const Text("Dark Mode"),
|
||||
Consumer<ThemeProvider>(
|
||||
builder: (context, themeProvider, child) {
|
||||
return CupertinoSwitch(
|
||||
value: themeProvider.isDarkMode,
|
||||
onChanged: (value) {
|
||||
themeProvider.toggleTheme();
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.secondaryContainer,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
margin: const EdgeInsets.all(16),
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Consumer<SettingsProvider>(
|
||||
builder: (context, settingsProvider, child) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(0.0),
|
||||
child: Column(
|
||||
children: settingsProvider.settingsOptions.map((option) {
|
||||
return SwitchListTile(
|
||||
title: Text(option.title),
|
||||
subtitle: (option.subtitle.isNotEmpty
|
||||
? Text(option.subtitle)
|
||||
: null),
|
||||
value: option.getValue(),
|
||||
onChanged: option.onChanged,
|
||||
contentPadding: EdgeInsets.zero,
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:cloud_firestore/cloud_firestore.dart';
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:percent_indicator/circular_percent_indicator.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:swipable_stack/swipable_stack.dart';
|
||||
|
||||
import '../components/card_overlay.dart';
|
||||
|
@ -14,7 +15,9 @@ import '../models/user_profile.dart';
|
|||
import '../services/auth/auth_service.dart';
|
||||
import '../services/swipe_stream_service.dart';
|
||||
import '../services/user_service.dart';
|
||||
import '../settings/settings_provider.dart';
|
||||
import '../utils/helper.dart';
|
||||
import '../utils/helper_locations.dart';
|
||||
import '../utils/list_utils.dart';
|
||||
import '../utils/math.dart';
|
||||
import 'chat_page.dart';
|
||||
|
@ -37,6 +40,7 @@ class UserMatchingPageState extends State<UserMatchingPage> {
|
|||
List<UserProfile> potentialUserProfiles = [];
|
||||
|
||||
late final SwipableStackController _controller;
|
||||
late final bool _showSameCountry;
|
||||
|
||||
// get instance of firestore and auth
|
||||
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
|
||||
|
@ -48,6 +52,8 @@ class UserMatchingPageState extends State<UserMatchingPage> {
|
|||
void initState() {
|
||||
super.initState();
|
||||
_controller = SwipableStackController()..addListener(_listenController);
|
||||
_showSameCountry =
|
||||
Provider.of<SettingsProvider>(context, listen: false).showSameCountry;
|
||||
_fetchUserProfiles();
|
||||
}
|
||||
|
||||
|
@ -91,6 +97,17 @@ class UserMatchingPageState extends State<UserMatchingPage> {
|
|||
.map((doc) => doc.id)
|
||||
.toSet();
|
||||
|
||||
// Fetch the current user's location
|
||||
QuerySnapshot locationSnapshot = await _firestore
|
||||
.collection(Constants.dbCollectionUsers)
|
||||
.doc(currentUserId)
|
||||
.collection(Constants.dbCollectionLocations)
|
||||
.get();
|
||||
List<String?> userLoc = [];
|
||||
for (var doc in locationSnapshot.docs) {
|
||||
userLoc.add(getCountryIsoCode(doc[Constants.dbFieldLocationCountry]));
|
||||
}
|
||||
|
||||
for (var userDoc in usersSnapshot.docs) {
|
||||
UserProfile userProfile =
|
||||
await UserService.getUserProfileFromDocument(userDoc);
|
||||
|
@ -99,12 +116,20 @@ class UserMatchingPageState extends State<UserMatchingPage> {
|
|||
allUsers.add(userProfile);
|
||||
// Exclude (1) the current user's profile, (2) the already liked profiles
|
||||
// (3) users that were disliked less than 24 hours ago
|
||||
// and (4) not active profile
|
||||
// and (4) not active profiles
|
||||
if (userDoc.id != currentUserId &&
|
||||
!likedUserIds.contains(userDoc.id) &&
|
||||
!dislikedUserIds.contains(userDoc.id) &&
|
||||
(userProfile.active ?? false)) {
|
||||
showProfiles.add(userProfile);
|
||||
// (5) apply additional settings
|
||||
if (_showSameCountry &&
|
||||
userProfile.locations.values.firstWhereOrNull((x) =>
|
||||
x != null &&
|
||||
userLoc.contains(getCountryIsoCode(x.country))) ==
|
||||
null) {
|
||||
showProfiles.remove(userProfile);
|
||||
}
|
||||
}
|
||||
} // end for
|
||||
|
||||
|
@ -284,7 +309,7 @@ class UserMatchingPageState extends State<UserMatchingPage> {
|
|||
}
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Find your Match')),
|
||||
appBar: AppBar(title: const Text('Swipe and Find your Match')),
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
child: Stack(
|
||||
|
@ -534,9 +559,9 @@ class UserMatchingPageState extends State<UserMatchingPage> {
|
|||
left: 0,
|
||||
right: 0,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
FloatingActionButton(
|
||||
/*FloatingActionButton(
|
||||
heroTag: 'myFABUndo',
|
||||
tooltip: 'Undo last action',
|
||||
shape: const CircleBorder(),
|
||||
|
@ -544,12 +569,13 @@ class UserMatchingPageState extends State<UserMatchingPage> {
|
|||
_controller.rewind(duration: Durations.extralong4);
|
||||
},
|
||||
child: const Icon(Icons.undo),
|
||||
),
|
||||
),*/
|
||||
SizedBox(
|
||||
width: 72,
|
||||
height: 72,
|
||||
child: FloatingActionButton(
|
||||
heroTag: 'myFABSwipeLeft',
|
||||
tooltip: 'Does not fit',
|
||||
shape: const CircleBorder(),
|
||||
onPressed: _swipeLeft,
|
||||
child: Stack(
|
||||
|
@ -569,11 +595,22 @@ class UserMatchingPageState extends State<UserMatchingPage> {
|
|||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
FloatingActionButton.extended(
|
||||
//icon: const Icon(Icons.skip_next),
|
||||
label: const Text('Skip'),
|
||||
tooltip: 'Skip profile',
|
||||
heroTag: 'myFABSkip',
|
||||
shape: const CircleBorder(),
|
||||
onPressed: _skip,
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
SizedBox(
|
||||
width: 72,
|
||||
height: 72,
|
||||
child: FloatingActionButton(
|
||||
heroTag: 'myFABSwipeRight',
|
||||
tooltip: "Interesting",
|
||||
shape: const CircleBorder(),
|
||||
onPressed: _swipeRight,
|
||||
child: Stack(
|
||||
|
@ -593,13 +630,6 @@ class UserMatchingPageState extends State<UserMatchingPage> {
|
|||
),
|
||||
),
|
||||
),
|
||||
FloatingActionButton(
|
||||
tooltip: 'Skip profile',
|
||||
heroTag: 'myFABSkip',
|
||||
shape: const CircleBorder(),
|
||||
onPressed: _skip,
|
||||
child: const Icon(Icons.skip_next),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
class SettingsOption {
|
||||
final String title;
|
||||
final String subtitle;
|
||||
final bool Function() getValue;
|
||||
final void Function(bool) onChanged;
|
||||
|
||||
SettingsOption({
|
||||
required this.title,
|
||||
this.subtitle = '',
|
||||
required this.getValue,
|
||||
required this.onChanged,
|
||||
});
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../constants.dart';
|
||||
import 'settings_options.dart';
|
||||
|
||||
class SettingsProvider extends ChangeNotifier {
|
||||
bool showSameCountry;
|
||||
|
||||
SettingsProvider({
|
||||
this.showSameCountry = false, // default value
|
||||
});
|
||||
|
||||
void toggleShowSameCountries() async {
|
||||
showSameCountry = !showSameCountry;
|
||||
notifyListeners();
|
||||
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
await prefs.setBool(Constants.prefKeySameCountry, showSameCountry);
|
||||
}
|
||||
|
||||
List<SettingsOption> get settingsOptions => [
|
||||
SettingsOption(
|
||||
title: "Match within my country",
|
||||
subtitle: 'Show profiles from your country only',
|
||||
getValue: () => showSameCountry,
|
||||
onChanged: (value) => toggleShowSameCountries(),
|
||||
),
|
||||
];
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
Map<String, String> countryToIsoCode = {
|
||||
// Europe
|
||||
'Germany': 'DE',
|
||||
'Deutschland': 'DE',
|
||||
'Österreich': 'AT',
|
||||
'Austria': 'AT',
|
||||
'Belgien': 'BE',
|
||||
'Belgium': 'BE',
|
||||
'Belgique': 'BE',
|
||||
'België': 'BE',
|
||||
'Bulgarien': 'BG',
|
||||
'Bulgaria': 'BG',
|
||||
'България': 'BG',
|
||||
'Kroatien': 'HR',
|
||||
'Croatia': 'HR',
|
||||
'Hrvatska': 'HR',
|
||||
'Zypern': 'CY',
|
||||
'Cyprus': 'CY',
|
||||
'Κύπρος': 'CY',
|
||||
'Tschechien': 'CZ',
|
||||
'Czech Republic': 'CZ',
|
||||
'Česká republika': 'CZ',
|
||||
'Dänemark': 'DK',
|
||||
'Denmark': 'DK',
|
||||
'Danmark': 'DK',
|
||||
'Estland': 'EE',
|
||||
'Estonia': 'EE',
|
||||
'Eesti': 'EE',
|
||||
'Finnland': 'FI',
|
||||
'Finland': 'FI',
|
||||
'Suomi': 'FI',
|
||||
'Frankreich': 'FR',
|
||||
'France': 'FR',
|
||||
'Griechenland': 'GR',
|
||||
'Greece': 'GR',
|
||||
'Ελλάδα': 'GR',
|
||||
'Ungarn': 'HU',
|
||||
'Hungary': 'HU',
|
||||
'Magyarország': 'HU',
|
||||
'Island': 'IS',
|
||||
'Iceland': 'IS',
|
||||
'Ísland': 'IS',
|
||||
'Irland': 'IE',
|
||||
'Ireland': 'IE',
|
||||
'Éire': 'IE',
|
||||
'Italien': 'IT',
|
||||
'Italy': 'IT',
|
||||
'Italia': 'IT',
|
||||
'Lettland': 'LV',
|
||||
'Latvia': 'LV',
|
||||
'Latvija': 'LV',
|
||||
'Litauen': 'LT',
|
||||
'Lithuania': 'LT',
|
||||
'Lietuva': 'LT',
|
||||
'Luxemburg': 'LU',
|
||||
'Luxembourg': 'LU',
|
||||
'Malta': 'MT',
|
||||
'Netherlands': 'NL',
|
||||
'Niederlande': 'NL',
|
||||
'Nederland': 'NL',
|
||||
'Polen': 'PL',
|
||||
'Poland': 'PL',
|
||||
'Polska': 'PL',
|
||||
'Portugal': 'PT',
|
||||
'Rumänien': 'RO',
|
||||
'Romania': 'RO',
|
||||
'România': 'RO',
|
||||
'Slowakei': 'SK',
|
||||
'Slovakia': 'SK',
|
||||
'Slovensko': 'SK',
|
||||
'Slowenien': 'SI',
|
||||
'Slovenia': 'SI',
|
||||
'Slovenija': 'SI',
|
||||
'Spanien': 'ES',
|
||||
'Spain': 'ES',
|
||||
'España': 'ES',
|
||||
'Schweden': 'SE',
|
||||
'Sweden': 'SE',
|
||||
'Sverige': 'SE',
|
||||
'Schweiz': 'CH',
|
||||
'Switzerland': 'CH',
|
||||
'Suisse': 'CH',
|
||||
'Svizzera': 'CH',
|
||||
'Беларусь': 'BY',
|
||||
'Belarus': 'BY',
|
||||
'Weißrussland': 'BY',
|
||||
'Bosnien und Herzegowina': 'BA',
|
||||
'Bosnia and Herzegovina': 'BA',
|
||||
'Bosna i Hercegovina': 'BA',
|
||||
'Nordmazedonien': 'MK',
|
||||
'North Macedonia': 'MK',
|
||||
'Северна Македонија': 'MK',
|
||||
'Serbien': 'RS',
|
||||
'Serbia': 'RS',
|
||||
'Србија': 'RS',
|
||||
'Montenegro': 'ME',
|
||||
'Albanien': 'AL',
|
||||
'Albania': 'AL',
|
||||
'Shqipëri': 'AL',
|
||||
'Türkei': 'TR',
|
||||
'Turkey': 'TR',
|
||||
'Türkiye': 'TR',
|
||||
'Russland': 'RU',
|
||||
'Russia': 'RU',
|
||||
'Россия': 'RU',
|
||||
'Ukraine': 'UA',
|
||||
'Україна': 'UA',
|
||||
|
||||
// Asia
|
||||
'China': 'CN',
|
||||
'中国': 'CN',
|
||||
'Zhōngguó': 'CN',
|
||||
'Japan': 'JP',
|
||||
'日本': 'JP',
|
||||
'Nihon': 'JP',
|
||||
'Südkorea': 'KR',
|
||||
'South Korea': 'KR',
|
||||
'대한민국': 'KR',
|
||||
'Daehanminguk': 'KR',
|
||||
'Indien': 'IN',
|
||||
'India': 'IN',
|
||||
'भारत': 'IN',
|
||||
'Bhārat': 'IN',
|
||||
|
||||
// North America
|
||||
'Kanada': 'CA',
|
||||
'Canada': 'CA',
|
||||
'Mexiko': 'MX',
|
||||
'Mexico': 'MX',
|
||||
'Estados Unidos Mexicanos': 'MX',
|
||||
'Vereinigte Staaten': 'US',
|
||||
'United States': 'US',
|
||||
'USA': 'US',
|
||||
};
|
||||
|
||||
String getCountryIsoCode(String country) {
|
||||
return countryToIsoCode[country] ?? country;
|
||||
}
|
||||
|
||||
bool compareCountries(String country1, String country2) {
|
||||
if (getCountryIsoCode(country1) == getCountryIsoCode(country2)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue