{"id":30686857,"url":"https://github.com/codeandtheory/toniesrn","last_synced_at":"2025-09-01T23:41:13.449Z","repository":{"id":310995161,"uuid":"1040691058","full_name":"codeandtheory/ToniesRN","owner":"codeandtheory","description":null,"archived":false,"fork":false,"pushed_at":"2025-08-21T12:06:43.000Z","size":164,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-21T14:23:56.733Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/codeandtheory.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-19T11:11:04.000Z","updated_at":"2025-08-21T12:06:47.000Z","dependencies_parsed_at":"2025-08-21T14:36:44.567Z","dependency_job_id":null,"html_url":"https://github.com/codeandtheory/ToniesRN","commit_stats":null,"previous_names":["codeandtheory/toniesrn"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/codeandtheory/ToniesRN","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeandtheory%2FToniesRN","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeandtheory%2FToniesRN/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeandtheory%2FToniesRN/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeandtheory%2FToniesRN/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/codeandtheory","download_url":"https://codeload.github.com/codeandtheory/ToniesRN/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codeandtheory%2FToniesRN/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":273208661,"owners_count":25064201,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-01T02:00:09.058Z","response_time":120,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-09-01T23:41:08.078Z","updated_at":"2025-09-01T23:41:13.439Z","avatar_url":"https://github.com/codeandtheory.png","language":"TypeScript","readme":"# ToniesApp — Expo React Native (MVVM + Clean Architecture)\n\nA sample Expo React Native app using MVVM with a Clean Architecture layout. It uses Expo Router for navigation, Zustand for state management, Awilix for dependency injection, and the native Fetch API for network calls.\n\n## Tech stack\n- React Native (via Expo)\n- TypeScript\n- Expo Router (file-based navigation)\n- Zustand (state management / ViewModel)\n- Awilix (dependency injection)\n- Fetch API (networking)\n- Reanimated (animations)\n- NativeWind + Tailwind CSS (styling)\n- expo-av (audio recording and playback)\n- react-native-safe-area-context (safe area handling)\n\n## Getting started\n1. Install dependencies\n\n```bash\nnpm install\n```\n\n2. Start the app\n\n```bash\nnpx expo start\n```\n\nThen press `i` (iOS), `a` (Android), or `w` (Web).\n\n## Project structure\n\n```\nassets/                      # App assets (images, fonts)\napp/                         # Expo Router entry \u0026 route files (kept minimal)\n  _layout.tsx\n  +not-found.tsx\n  (tabs)/\n    _layout.tsx\n    index.tsx                # Exports UsersScreen\n\nsrc/\n  data/                      # Data layer (infrastructure)\n    api/                     # HTTP client\n      ApiClient.ts           # fetch-based http\u003cT\u003e() helper\n    dtos/                    # Remote DTOs\n      UserDto.ts\n    mappers/                 # DTO \u003c-\u003e Domain mappers\n      UserMapper.ts\n    repositories/            # Repository implementations\n      UserRepositoryImpl.ts\n      RecorderRepositoryImpl.ts\n\n  domain/                    # Domain layer (pure business logic)\n    entities/\n      User.ts\n      RecordingItem.ts\n    repositories/            # Repository contracts\n      UserRepository.ts\n      RecorderRepository.ts\n    usecases/\n      GetUsersUseCase.ts\n      StartRecordingUseCase.ts\n      StopAndSaveRecordingUseCase.ts\n      ListRecordingsUseCase.ts\n      PlayRecordingUseCase.ts\n      PauseRecordingUseCase.ts\n      ResumeRecordingUseCase.ts\n\n  presentation/              # Presentation layer (UI + ViewModels)\n    components/\n      ThemedText.tsx\n      ThemedView.tsx\n      Collapsible.tsx\n      ExternalLink.tsx\n      HelloWave.tsx\n      ParallaxScrollView.tsx\n      HapticTab.tsx\n      ui/\n        IconSymbol.tsx\n        IconSymbol.ios.tsx\n        TabBarBackground.tsx\n        TabBarBackground.ios.tsx\n    hooks/\n      useColorScheme.ts\n      useColorScheme.web.ts\n      useThemeColor.ts\n    screens/\n      UsersScreen.tsx\n      RecorderScreen.tsx\n    viewmodels/\n      usersStore.ts          # Zustand store (ViewModel)\n      recorderStore.ts\n\n  di/                        # Dependency injection setup\n    container.ts             # Awilix container (registrations)\n\n  shared/\n    constants/\n      Colors.ts\n\nexpo-env.d.ts\napp.json\npackage.json\ntsconfig.json\ntailwind.config.js\n```\n\n## Architecture overview\n- Presentation (React components/screens + Zustand stores as ViewModels)\n  - View models expose simple state and actions for the UI\n  - Example: `src/presentation/viewmodels/usersStore.ts`\n- Domain (business logic, pure and testable)\n  - Entities, repository interfaces, and use cases\n  - Example: `GetUsersUseCase` depends on `UserRepository` (contract)\n- Data (external/infrastructure)\n  - Fetch-based HTTP client, DTOs, mappers, repository implementations\n  - Example: `UserRepositoryImpl` calls the API and maps DTOs to domain entities\n- DI (dependency injection)\n  - Awilix container registers concrete implementations and use cases\n  - Resolved in presentation layer where needed\n\n### Data flow\nUI (Screen) -\u003e ViewModel (Zustand store) -\u003e Use Case -\u003e Repository (impl) -\u003e HTTP Client -\u003e API\n\n## Navigation\n- Uses Expo Router with file-based routing under `app/`\n- Route files are thin and export screens from `src/presentation/screens`\n- Main layout: `app/_layout.tsx`\n- Tabs layout: `app/(tabs)/_layout.tsx`\n\n## Dependency Injection (Awilix)\n- Container: `src/di/container.ts`\n- Proxy injection with object-arg constructors\n  - Registers singletons for repositories and use cases\n  - Example resolve: `container.resolve\u003cGetUsersUseCase\u003e('getUsersUseCase')`\n\n## State management (Zustand)\n- Users ViewModel: `src/presentation/viewmodels/usersStore.ts`\n- Recorder ViewModel: `src/presentation/viewmodels/recorderStore.ts`\n  - State: `items`, `isRecording`, `isPaused`, `isPreparing`, `isStopping`, `errorMessage`\n  - Actions: `load`, `start`, `pause`, `resume`, `stopAndSave`, `play`, `clearError`\n\n## Networking (Fetch)\n- HTTP helper: `src/data/api/ApiClient.ts`\n- Base URL: `https://jsonplaceholder.typicode.com`\n- Repository: `src/data/repositories/UserRepositoryImpl.ts`\n\n## Audio (expo-av)\n- Recording and playback implemented in `src/data/repositories/RecorderRepositoryImpl.ts`\n- iOS permission: `NSMicrophoneUsageDescription` in `app.json`\n- Audio mode set with `Audio.setAudioModeAsync`\n- Filenames saved as: `Recording YYYY-MM-DD HH:MM:SS.m4a`\n\n## Styling (NativeWind + Tailwind)\n- Tailwind config: `tailwind.config.js`\n  - content: `['./app/**/*.{js,tsx,ts,jsx}', './src/**/**/*.{js,jsx,ts,tsx}']`\n  - presets: `[require('nativewind/preset')]`\n- Import styles in root layout: `import 'nativewind/css'`\n- Components/screens use `className` utility classes\n\n## Path aliases\n- Configured in `tsconfig.json`:\n  - `@/*` -\u003e project root (used as `@/src/...`)\n\n## Scripts\n- `npm start` / `npx expo start`: run Metro bundler and launch app\n- `npm run ios` / `npm run android` / `npm run web`: platform targets\n- `npm run lint`: run ESLint\n- `npm run reset-project`: reset example starter\n\n## Notes\n- Keep `app/` (required by Expo Router). Use it only for routing; keep UI in `src/presentation`.\n- Add new features by creating domain entities/interfaces/use cases, data implementations/mappers, registering in the DI container, and wiring a new ViewModel + screen.\n- On iOS Simulator: enable Features \u003e Audio Input and grant microphone permissions in macOS System Settings if recording fails.\n\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodeandtheory%2Ftoniesrn","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodeandtheory%2Ftoniesrn","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodeandtheory%2Ftoniesrn/lists"}