Skip to content

Commit 102681b

Browse files
committed
fix map view and colors
1 parent d7f9753 commit 102681b

18 files changed

Lines changed: 1074 additions & 224 deletions

File tree

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ app.*.symbols
3838
# Obfuscation related
3939
app.*.map.json
4040

41-
# Android Studio will place build artifacts here
41+
# Android related
4242
/android/app/debug
4343
/android/app/profile
4444
/android/app/release
45+
/android/local.properties

android/app/build.gradle

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ android {
3232
targetCompatibility JavaVersion.VERSION_21
3333
}
3434

35+
tasks.withType(JavaCompile) {
36+
options.compilerArgs.addAll(['-Xlint:-options'])
37+
}
38+
3539
kotlinOptions {
3640
jvmTarget = '21'
3741
}

android/app/src/main/kotlin/com/beforbike/app/BleServerService.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -293,10 +293,12 @@ class BleServerService : Service() {
293293
val lon = jsonObj.optDouble("longitude", Double.NaN)
294294
val alt = jsonObj.optDouble("altitude", Double.NaN)
295295
val vel = jsonObj.optDouble("velocity", Double.NaN)
296+
val cad = jsonObj.optDouble("cadence", Double.NaN)
296297
var savedCount = 0
297298
if (power.isFinite()) { if (dbHelper.insertPower(rideIdFromJson, power.toFloat())) savedCount++ }
298299
if (lat.isFinite() && lon.isFinite()) { val altF = if (alt.isFinite()) alt.toFloat() else null; if (dbHelper.insertMapData(rideIdFromJson, lat.toFloat(), lon.toFloat(), altF)) savedCount++ }
299300
if (vel.isFinite()) { if (dbHelper.insertVelocity(rideIdFromJson, vel.toFloat())) savedCount++ }
301+
if (cad.isFinite()) { if (dbHelper.insertCadence(rideIdFromJson, cad.toFloat())) savedCount++ }
300302
log(if (savedCount > 0) " => $savedCount dado(s) salvo(s)." else " -> Nenhum dado válido.")
301303
}
302304
}

android/app/src/main/kotlin/com/beforbike/app/database/SeedData.kt

Lines changed: 20 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,49 +19,27 @@ object SeedData {
1919

2020
android.util.Log.d("BeForBike", "Proceeding with insertion")
2121
val baseTime = System.currentTimeMillis()
22-
// Insert larger GPS path for visible map display (U shape: east-south-east)
23-
val baseLat = -25.4284f
24-
val baseLon = -49.2733f
25-
val baseAlt = 880f
26-
// Create a 10-minute ride (600 seconds) with GPS points every 10 seconds = 60 points
27-
val totalPoints = 60
28-
val timeIntervalSeconds = 10
29-
val path = mutableListOf<Triple<Float, Float, Float>>().apply {
30-
// East segment: decrease lon (west) - 20 points
31-
for (i in 0..19) {
32-
val progress = i.toFloat() / 19f
33-
add(Triple(baseLat, baseLon - progress * 0.2f, baseAlt + progress * 50f))
34-
}
35-
// South segment: increase lat - 20 points
36-
val turnPoint = last()
37-
for (i in 1..20) {
38-
val progress = i.toFloat() / 20f
39-
add(Triple(turnPoint.first + progress * 0.2f, turnPoint.second, turnPoint.third + progress * 30f))
40-
}
41-
// East segment: increase lon (east, back) - 20 points
42-
val turn2Point = last()
43-
for (i in 1..20) {
44-
val progress = i.toFloat() / 20f
45-
add(Triple(turn2Point.first, turn2Point.second + progress * 0.2f, turn2Point.third + progress * 20f))
46-
}
47-
}
22+
// Use specific GPS coordinates for the test ride
23+
val path = listOf(
24+
// Start: -25.4290, -49.2721
25+
Triple(-25.4290f, -49.2721f, 880f),
26+
// Checkpoint 1: -25.4285, -49.2730
27+
Triple(-25.4285f, -49.2730f, 885f),
28+
// Checkpoint 2: -25.4292, -49.2738
29+
Triple(-25.4292f, -49.2738f, 890f),
30+
// Checkpoint 3: -25.4301, -49.2735
31+
Triple(-25.4301f, -49.2735f, 895f),
32+
// End: -25.4303, -49.2732 (closer to Checkpoint 3 for better visual connection)
33+
Triple(-25.4303f, -49.2732f, 900f)
34+
)
4835

49-
// Generate corresponding velocities, powers, and cadences (60 values)
50-
val velocities = mutableListOf<Float>()
51-
val powers = mutableListOf<Float>()
52-
val cadences = mutableListOf<Float>()
36+
val totalPoints = path.size
37+
val timeIntervalSeconds = 75 // 75 seconds between each checkpoint for a 5-minute ride (4 intervals * 75s = 300s = 5 minutes)
5338

54-
// Create realistic cycling data with some variation
55-
for (i in 0 until totalPoints) {
56-
val baseVelocity = 15.0f + (i % 10) * 0.5f // 15-19.5 km/h with pattern
57-
velocities.add(baseVelocity + (-1..1).random() * 0.5f) // Add some noise
58-
59-
val basePower = 150f + (i % 15) * 5f // 150-215 watts with pattern
60-
powers.add(basePower + (-5..5).random()) // Add some noise
61-
62-
val baseCadence = 85f + (i % 10) * 2f // 85-103 rpm with pattern
63-
cadences.add(baseCadence + (-3..3).random()) // Add some noise
64-
}
39+
// Generate corresponding velocities, powers, and cadences (5 values for 5 points)
40+
val velocities = listOf(17.5f, 18.2f, 16.8f, 19.1f, 17.9f)
41+
val powers = listOf(165f, 172f, 158f, 185f, 175f)
42+
val cadences = listOf(88f, 92f, 85f, 95f, 89f)
6543

6644
// Ensure ride exists first
6745
if (!dbHelper.ensureRideExists(SAMPLE_RIDE_ID, "Sample Ride")) {
@@ -71,7 +49,7 @@ object SeedData {
7149

7250
android.util.Log.d("BeForBike", "Inserting $totalPoints GPS points for sample ride")
7351
path.forEachIndexed { index, (lat, lon, alt) ->
74-
val timestamp = baseTime + index * timeIntervalSeconds * 1000L // 10 seconds apart
52+
val timestamp = baseTime + index * timeIntervalSeconds * 1000L // 75 seconds apart
7553
val success = dbHelper.insertMapData(SAMPLE_RIDE_ID, lat, lon, alt, timestamp = timestamp)
7654
if (success) {
7755
dbHelper.insertVelocity(SAMPLE_RIDE_ID, velocities[index], timestamp = timestamp)

android/build/reports/problems/problems-report.html

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

android/gradle.properties

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@ org.gradle.jvmargs=-Xmx8192M
22
android.useAndroidX=true
33
android.enableJetifier=true
44
android.aarMetadata.check.enabled=false
5-
kotlin.version=2.2.21
5+
kotlin.version=2.2.21
6+
# Suppress Java 8 deprecation warnings
7+
org.gradle.warning.mode=all
8+
android.suppressUnsupportedCompileSdk=36

lib/core/utils/audio_service.dart

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import 'package:vibration/vibration.dart';
2+
import 'package:flutter/foundation.dart';
3+
4+
/// Service for managing haptic feedback in the app.
5+
/// Provides fitness-inspired vibration patterns for button interactions.
6+
class AudioService {
7+
static final AudioService _instance = AudioService._internal();
8+
factory AudioService() => _instance;
9+
10+
AudioService._internal();
11+
12+
bool _isInitialized = false;
13+
bool _hasVibrator = false;
14+
15+
/// Initialize the haptic service
16+
Future<void> initialize() async {
17+
if (_isInitialized) return;
18+
19+
try {
20+
_hasVibrator = await Vibration.hasVibrator() ?? false;
21+
_isInitialized = true;
22+
debugPrint('AudioService initialized with vibration support: $_hasVibrator');
23+
} catch (e) {
24+
debugPrint('Failed to initialize AudioService: $e');
25+
_hasVibrator = false;
26+
}
27+
}
28+
29+
/// Play button click vibration - for general button interactions
30+
Future<void> playButtonClick() async {
31+
await _vibrate(pattern: [0, 10, 5, 5]); // Quick double tap
32+
}
33+
34+
/// Play navigation click vibration - for screen transitions
35+
Future<void> playNavigationClick() async {
36+
await _vibrate(pattern: [0, 15, 5, 10]); // Slightly longer for navigation
37+
}
38+
39+
/// Play success vibration - for completed actions
40+
Future<void> playActionSuccess() async {
41+
await _vibrate(pattern: [0, 20, 10, 20, 10, 10]); // Success pattern
42+
}
43+
44+
/// Internal method to vibrate with pattern
45+
Future<void> _vibrate({required List<int> pattern}) async {
46+
if (!_isInitialized) {
47+
await initialize();
48+
}
49+
50+
if (!_hasVibrator) {
51+
debugPrint('Vibration not supported on this device');
52+
return;
53+
}
54+
55+
try {
56+
await Vibration.vibrate(pattern: pattern);
57+
} catch (e) {
58+
debugPrint('Failed to vibrate: $e');
59+
// Silently fail - don't crash the app if vibration fails
60+
}
61+
}
62+
63+
/// Dispose of the haptic service
64+
void dispose() {
65+
_isInitialized = false;
66+
}
67+
}

lib/main.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:stack_trace/stack_trace.dart' as stack_trace;
1010
import 'l10n/support_locale.dart';
1111
import 'presentation/common/core/services/text_to_speech_service.dart';
1212
import 'presentation/common/core/utils/color_utils.dart';
13+
import 'core/utils/audio_service.dart';
1314
import 'presentation/home/screens/home_screen.dart';
1415
import 'presentation/my_activities/screens/activity_list_screen.dart';
1516
import 'presentation/new_activity/screens/sum_up_screen.dart';
@@ -24,6 +25,9 @@ void main() async {
2425
DeviceOrientation.portraitUp,
2526
]);
2627

28+
// Initialize audio service for button sounds
29+
await AudioService().initialize();
30+
2731
runApp(
2832
const ProviderScope(child: MyApp()),
2933
);

lib/presentation/common/activity/widgets/activity_item.dart

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
44
import '../../../../domain/entities/activity.dart';
55
import '../../core/utils/color_utils.dart';
66
import '../view_model/activity_item_view_model.dart';
7+
import '../../../my_activities/view_model/activity_list_view_model.dart';
78
import 'activity_item_details.dart';
89

910
class ActivityItem extends HookConsumerWidget {
@@ -26,6 +27,10 @@ class ActivityItem extends HookConsumerWidget {
2627
ref.read(activityItemViewModelProvider(activity.id).notifier);
2728
final state = ref.watch(activityItemViewModelProvider(activity.id));
2829

30+
// Get activity list view model for selection functionality
31+
final activityListProvider = ref.watch(activityListViewModelProvider.notifier);
32+
final activityListState = ref.watch(activityListViewModelProvider);
33+
2934
const double borderRadius = 24;
3035

3136
Activity currentActivity = state.activity ?? activity;
@@ -35,29 +40,44 @@ class ActivityItem extends HookConsumerWidget {
3540
final gradientColors = ColorUtils.generateGradientFromCalories(currentActivity.calories);
3641

3742
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
43+
final isSelected = activityListState.selectedActivities.contains(activity.id);
3844

3945
return InkWell(
4046
onTap: () async {
41-
if (canOpenActivity) {
47+
if (activityListState.isSelectionMode) {
48+
// In selection mode, toggle selection
49+
activityListProvider.toggleActivitySelection(activity.id);
50+
} else if (canOpenActivity) {
51+
// Normal mode, open activity
4252
final activityDetails =
4353
await provider.getActivityDetails(activity);
4454
provider.goToStatistics(activityDetails);
4555
}
4656
},
57+
onLongPress: () {
58+
// Enter selection mode and select this activity
59+
if (!activityListState.isSelectionMode) {
60+
activityListProvider.toggleSelectionMode();
61+
}
62+
activityListProvider.toggleActivitySelection(activity.id);
63+
},
4764
child: Card(
4865
shape: RoundedRectangleBorder(
4966
borderRadius: BorderRadius.circular(borderRadius),
5067
),
51-
elevation: 2,
68+
elevation: isSelected ? 8 : 2,
5269
margin: const EdgeInsets.all(8),
5370
child: Container(
5471
decoration: BoxDecoration(
5572
gradient: LinearGradient(
56-
colors: gradientColors,
73+
colors: isSelected
74+
? [Colors.red.shade200, Colors.red.shade400]
75+
: gradientColors,
5776
begin: Alignment.topLeft,
5877
end: Alignment.bottomRight,
5978
),
6079
borderRadius: BorderRadius.circular(borderRadius),
80+
border: isSelected ? Border.all(color: Colors.red, width: 3) : null,
6181
boxShadow: [
6282
BoxShadow(
6383
color: Colors.grey.withValues(alpha: 0.2),

lib/presentation/home/screens/home_screen.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:google_nav_bar/google_nav_bar.dart';
33
import 'package:hooks_riverpod/hooks_riverpod.dart';
44

55
import '../../common/core/utils/color_utils.dart';
6+
import '../../../core/utils/audio_service.dart';
67
import '../../my_activities/screens/activity_list_screen.dart';
78
import '../../settings/screens/settings_screen.dart';
89
import '../../statistics/screens/statistics_screen.dart';
@@ -78,6 +79,7 @@ class HomeScreen extends HookConsumerWidget {
7879
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 8),
7980
selectedIndex: adjustedIndex,
8081
onTabChange: (value) {
82+
AudioService().playNavigationClick();
8183
// Adjust the index when map is hidden
8284
var actualIndex = value;
8385
if (!settingsState.showMap && value >= 1) {

0 commit comments

Comments
 (0)