Skip to content

rapidarray1211/Flutter-Campus-GeoGuesser

Repository files navigation

UoGuesser

A location-based guessing game where users try to identify where pictures were taken on a map. Players can upload their own pictures, which become part of the game's content. The game includes multiple modes and features both online and offline functionality.

Features

  • Daily challenges with 5 random pictures
  • Unlimited mode for continuous play
  • Picture upload with location data
  • Google Maps integration
  • Global and friends leaderboards
  • User profiles with biography and picture gallery
  • Offline play capability
  • Score synchronization

Prerequisites

Before you begin, ensure you have the following installed:

Getting Started

1. Clone the Repository

git clone https://gitlab.socs.uoguelph.ca/w25-4030-section-01/group_17/uoguesser.git
cd uoguesser

2. Set Up Environment Variables

Create a .env file in the project root:

touch .env

Add the following variables to your .env file (get these values from the team lead):

SUPABASE_URL=your_production_supabase_url
SUPABASE_ANON_KEY=your_production_supabase_anon_key

Important: We are currently working directly with the production database. The local Supabase setup described below is optional and only needed if you want to experiment with database changes without affecting the production environment.

3. Install Flutter Dependencies

flutter pub get

4. Local Supabase Development (Optional)

Note: This section is for developers who need to test database changes locally. For regular development, you can skip this section as we are working with the production database.

If you need to test database changes without affecting the production environment, you can set up a local Supabase instance:

  1. Start Docker Desktop

  2. Initialize Supabase project:

supabase init
  1. Start local Supabase:
supabase start

This will create a local Supabase instance with the following credentials:

API URL: http://127.0.0.1:54321
     GraphQL URL: http://127.0.0.1:54321/graphql/v1
  S3 Storage URL: http://127.0.0.1:54321/storage/v1/s3
          DB URL: postgresql://postgres:[email protected]:54322/postgres
      Studio URL: http://127.0.0.1:54323
    Inbucket URL: http://127.0.0.1:54324
      JWT secret: <secret>
        anon key: <key>
service_role key: <key>
   S3 Access Key: <key>
   S3 Secret Key: <key>
       S3 Region: local
  1. To use the local instance instead of production, update your .env file with the local credentials provided by supabase start.

5. Run the Application

flutter run

Development Workflow

Database Changes

Important: We are currently working with the production database. Please coordinate with everyone before making any database changes.

Database Migrations

All database migrations are stored in supabase/migrations/. To manage migrations:

  1. Create a new migration:
supabase migration new your_migration_name
  1. Apply migrations:
supabase migration up
  1. Revert last migration:
supabase migration down
  1. Reset database:
supabase db reset

Working with Supabase

  1. Start local Supabase:
supabase start
  1. Stop local Supabase:
supabase stop
  1. View logs:
supabase logs

Code Structure

lib/
├── main.dart               # Application entry point
├── providers/             # State management
│   ├── player.provider.dart   # Player state management
│   └── ...
├── server/               # Backend integration
│   ├── services/         # Business logic layer
│   │   ├── player.service.dart
│   │   ├── game.service.dart
│   │   └── ...
│   ├── models/          # Data models
│   │   ├── player.dart
│   │   ├── game.dart
│   │   └── ...
│   └── data/           # Data access layer
│       ├── player.repository.dart
│       ├── game.repository.dart
│       └── ...
├── screens/            # UI screens

State Management with Providers

The application uses the Provider pattern for state management. Each major feature has its own provider that manages its state and business logic. For example, the PlayerProvider:

class PlayerProvider extends ChangeNotifier {
  final _playerService = GetIt.instance<PlayerService>();
  
  Player? _currentPlayer;
  List<Picture> _pictures = [];
  
  // Expose state
  Player? get currentPlayer => _currentPlayer;
  List<Picture> get pictures => _pictures;
  
  // Methods to modify state
  Future<void> updateProfile({required String name, String? biography}) async {
    // Update player profile
    // Notify listeners of changes
  }
}

Architecture Overview

Server Layer Organization

The server-side code follows a clean architecture pattern with three main layers:

1. Models Layer (/server/models/)

  • Pure Dart classes representing database entities
  • Handles JSON serialization/deserialization
  • No business logic or data access
  • Example: Player, Game, Picture models
// Example model structure (player.dart)
class Player {
  final String id;
  final String username;
  
  Player.fromJson(Map<String, dynamic> json) {
    // Conversion from JSON to Dart object
  }
  
  Map<String, dynamic> toJson() {
    // Conversion from Dart object to JSON
  }
}

2. Data Layer (/server/data/)

  • Repository classes for direct Supabase interaction
  • Handles raw database queries and mutations
  • No business logic
  • One repository per entity type
  • Example: PlayerRepository, GameRepository, PictureRepository
// Example repository structure (player.repository.dart)
class PlayerRepository {
  final SupabaseClient _supabase;
  
  Future<Player> getPlayer(String id) async {
    // Raw database query
    final response = await _supabase
        .from('players')
        .select()
        .eq('player_id', id)
        .single();
    
    return Player.fromJson(response);
  }
}

3. Services Layer (/server/services/)

  • Business logic implementation
  • Orchestrates data operations
  • Error handling and validation
  • One service per major feature
  • Example: PlayerService, GameService, PictureService
// Example service structure (player.service.dart)
class PlayerService {
  final PlayerRepository _repository;
  
  Future<Player> getPlayerProfile(String id) async {
    try {
      // Business logic, validation, error handling
      return await _repository.getPlayer(id);
    } catch (e) {
      throw PlayerServiceException('Failed to get player profile: $e');
    }
  }
}

Dependency Injection

The application uses the get_it package for service location and dependency injection:

  1. Service Registration (service_locator.dart):
    • Registers all repositories and services as singletons
    • Manages dependencies between services
    • Initializes Supabase client
// Example service registration
final getIt = GetIt.instance;

setupServices() {
  // Register repositories
  getIt.registerLazySingleton(() => PlayerRepository(supabase));
  
  // Register services with their dependencies
  getIt.registerLazySingleton(() => PlayerService(getIt<PlayerRepository>()));
}
  1. Service Usage in App:
    • Services are accessed through getIt
    • No need to manually manage dependencies
    • Consistent singleton instances throughout the app
// Example service usage in widgets
final playerService = getIt<PlayerService>();

Supabase Deployment

Connecting to Supabase Project

  1. Install Supabase CLI (if not already installed):
brew install supabase/tap/supabase   # macOS
  1. Login to Supabase:
supabase login
  1. List your Supabase projects:
supabase projects list

This will show all your projects and their reference IDs in the format:

                          Name                           | Reference ID | Database Status |   URL
+-------------------------------------------------------+--------------+-----------------+-----------+
  your-project-name                                      | abcdefghijkl | Active         | app.supabase.com
  1. Link your local project to Supabase (using the Reference ID from step 3):
supabase link --project-ref your-project-ref

Note: The project reference is the unique identifier shown in the 'Reference ID' column from the projects list

  1. Push database changes:
supabase db push

Edge Functions

Edge functions are serverless functions that run on Supabase's edge network. They're located in the supabase/functions directory.

Creating a New Edge Function

  1. Create a new function:
supabase functions new your-function-name

This creates a new TypeScript function in supabase/functions/your-function-name/index.ts

  1. Example edge function structure:
// supabase/functions/calculate-score/index.ts
import { serve } from 'https://deno.land/[email protected]/http/server.ts'

interface ScoreParams {
  guessLocation: [number, number]
  actualLocation: [number, number]
}

serve(async (req) => {
  try {
    const { guessLocation, actualLocation } = await req.json() as ScoreParams
    
    // Your function logic here
    const score = calculateScore(guessLocation, actualLocation)
    
    return new Response(
      JSON.stringify({ score }),
      { headers: { 'Content-Type': 'application/json' } }
    )
  } catch (error) {
    return new Response(
      JSON.stringify({ error: error.message }),
      { status: 400, headers: { 'Content-Type': 'application/json' } }
    )
  }
})

Testing Edge Functions Locally

  1. Start the edge functions development server:
supabase functions serve
  1. Test with curl:
curl -L -X POST 'http://localhost:54321/functions/v1/your-function-name' \
-H 'Authorization: Bearer your-anon-key' \
-d '{"key": "value"}'

Deploying Edge Functions

  1. Deploy a single function:
supabase functions deploy your-function-name
  1. Deploy all functions:
supabase functions deploy

Environment Management

supabase functions deploy --no-verify-jwt

Troubleshooting

Common Issues

  1. Supabase Connection Issues

    • Ensure Docker is running
    • Check if Supabase is started (supabase status)
    • Verify environment variables are correct
  2. Flutter Build Issues

    • Run flutter clean
    • Delete pubspec.lock and run flutter pub get
    • Ensure all dependencies are compatible
  3. Database Migration Issues

    • Reset the database (supabase db reset)
    • Check migration file syntax
    • Verify migration order

Acknowledgments

  • University of Guelph
  • CIS*4030 Course Team
  • All contributors to this project

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published