A native Android client for GitLab that brings your repositories to your fingertips. Browse projects, view merge requests, and manage issues without opening a web browser.
| Home Screen | Project List | Issues | MRs | Members | Project Overview | Profile | Repository | Commits | Pipelines |
|---|---|---|---|---|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
- Overview
- ✨ Key Features
- 🛠️ Tech Stack
- 🚀 Quick Start
- 📁 Project Structure
- ⚙️ Configuration
- 🔒 Security
- 📚 Architecture
- 🤝 Contributing
- 📄 License
GitLab Client is a modern Android application built with Kotlin and Jetpack Compose that provides a native, efficient way to interact with GitLab. Whether you're a developer on the go or prefer a dedicated mobile experience, this app eliminates the need to open a web browser while maintaining full access to your GitLab workspace.
The application leverages Apollo Kotlin for GraphQL queries and OAuth2 for secure authentication, ensuring a seamless and secure user experience.
- 📱 Modern Jetpack Compose UI — Clean, responsive, and fully native Android interface built with Jetpack Compose for an intuitive user experience.
- 🔐 GitLab OAuth2 Authentication — Secure login using GitLab's official OAuth2 authorization flow.
- ⚡ GraphQL Integration — Efficient data fetching using Apollo Kotlin for optimized performance.
- 📂 Repository Browsing — Quickly view and navigate your GitLab projects on mobile.
- 🔍 Project Details — Access comprehensive project information including merge requests, issues, and statistics.
- 💾 Secure Token Storage — Encrypted storage of authentication tokens for safe credential management.
- 🎨 Dark & Light Themes — Adaptive UI themes for comfortable viewing in any lighting condition.
| Layer | Technologies |
|---|---|
| UI Framework | Jetpack Compose, Material Design 3 |
| Language | Kotlin |
| Data Layer | Apollo Kotlin (GraphQL), OkHttp |
| Authentication | OAuth2 |
| Security | Crypto/Encryption utilities |
| Dependency Injection | Hilt |
| Image Loading | Coil |
| Platform | Android (Native) |
| Build System | Gradle (Kotlin DSL) |
- Android Studio Giraffe or later
- Android SDK 24 (or higher)
- Kotlin 1.9+
- Git
# 1. Clone the repository
git clone https://github.com/Ahtat204/Gitlab.git
cd Gitlab
# 2. Open in Android Studio
# File > Open > Select the project directory
# 3. Configure GitLab OAuth2 credentials
# Update AuthConfig.kt with your GitLab app credentials
# 4. Sync Gradle and run the app
./gradlew build
# Then run on emulator or physical device-
Register a GitLab Application:
- Go to GitLab → Preferences → Applications
- Create a new application with redirect URI:
gitlab://oauth-callback - Note your Application ID and Secret
-
Update AuthConfig.kt:
object AuthConfig { const val GITLAB_CLIENT_ID = "your_client_id" const val GITLAB_CLIENT_SECRET = "your_client_secret" const val REDIRECT_URI = "gitlab://oauth-callback" }
-
Build and Run:
./gradlew installDebug
Gitlab/
├── app
│ ├── build.gradle.kts
│ ├── proguard-rules.pro
│ └── src
│ ├── androidTest
│ │ └── java
│ │ └── com
│ │ └── ahtat204
│ │ └── gitlab
│ │ └── ExampleInstrumentedTest.kt
│ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── graphql
│ │ │ └── com
│ │ │ └── ahtat204
│ │ │ ├── mutation
│ │ │ ├── project
│ │ │ │ ├── GetProjectDetails.graphql
│ │ │ │ ├── GetProjectIssues.graphql
│ │ │ │ ├── GetProjectMembers.graphql
│ │ │ │ ├── GetProjectMRs.graphql
│ │ │ │ ├── GetProjectPipelines.graphql
│ │ │ │ ├── mergerequests
│ │ │ │ │ └── GetProjectMergeRequests.graphql
│ │ │ │ └── repository
│ │ │ │ ├── GetProjectRepository.graphql
│ │ │ │ ├── GetRepositoryBlob.graphql
│ │ │ │ ├── GetRepositoryBranches.graphql
│ │ │ │ ├── GetRepositoryCommits.graphql
│ │ │ │ └── GetRepositoryTree.graphql
│ │ │ ├── schema.graphqls
│ │ │ └── user
│ │ │ ├── currentUser
│ │ │ │ ├── GetAllProjects.graphql
│ │ │ │ ├── GetMyContributedProjects.graphql
│ │ │ │ ├── GetMyPersonalProjects.graphql
│ │ │ │ └── GetMyProfile.graphql
│ │ │ └── GetUserProjectsByName.graphql
│ │ └── java
│ │ └── com
│ │ └── ahtat204
│ │ └── gitlab
│ │ ├── data
│ │ │ ├── helpers
│ │ │ │ ├── fetchAndMergeCommits.kt
│ │ │ │ ├── fetchAndMergeIssues.kt
│ │ │ │ ├── fetchAndMergeMembers.kt
│ │ │ │ ├── fetchAndMergeMRs.kt
│ │ │ │ ├── fetchAndMergePipelines.kt
│ │ │ │ ├── fetchAndMergeProjects.kt
│ │ │ │ └── mapAndHandleErrors.kt
│ │ │ ├── remote
│ │ │ │ └── repositories
│ │ │ │ └── graphql
│ │ │ │ ├── ApolloGraphQLRepository.kt
│ │ │ │ └── GraphQlRepository.kt
│ │ │ └── security
│ │ │ └── AuthenticationInterceptor.kt
│ │ ├── domain
│ │ │ ├── authentication
│ │ │ │ ├── AuthStateSerializer.kt
│ │ │ │ ├── constants
│ │ │ │ │ ├── AuthConfig.kt
│ │ │ │ │ └── Tokens.kt
│ │ │ │ ├── SafeStore.kt
│ │ │ │ └── security
│ │ │ │ └── CryptoUtility.kt
│ │ │ ├── di
│ │ │ │ ├── ApolloModule.kt
│ │ │ │ ├── OkHttpModule.kt
│ │ │ │ └── ProjectRepositoryModule.kt
│ │ │ └── logging
│ │ │ └── Logger.kt
│ │ ├── GitlabApp.kt
│ │ └── presentation
│ │ ├── activities
│ │ │ ├── AuthenticationActivity.kt
│ │ │ ├── LauncherActivity.kt
│ │ │ ├── MainActivity.kt
│ │ │ └── ui
│ │ │ └── theme
│ │ │ ├── Color.kt
│ │ │ ├── Theme.kt
│ │ │ └── Type.kt
│ │ ├── components
│ │ │ ├── About.kt
│ │ │ ├── AutoLinkText.kt
│ │ │ ├── BlobCard.kt
│ │ │ ├── BranchesList.kt
│ │ │ ├── CoilCache.kt
│ │ │ ├── CollaborationDetails.kt
│ │ │ ├── CommitCard.kt
│ │ │ ├── Contact.kt
│ │ │ ├── FileBrowser.kt
│ │ │ ├── GeneralDetails.kt
│ │ │ ├── Header.kt
│ │ │ ├── Info.kt
│ │ │ ├── ISO8601ToRelativeDate.kt
│ │ │ ├── IssueCard.kt
│ │ │ ├── LanguageCircle.kt
│ │ │ ├── LanguagesBar.kt
│ │ │ ├── measureTestWidth.kt
│ │ │ ├── MergeRequest.kt
│ │ │ ├── Panel.kt
│ │ │ ├── PanelSlider.kt
│ │ │ ├── Pipeline.kt
│ │ │ ├── PipelineStatusIcon.kt
│ │ │ ├── ProjectItem.kt
│ │ │ ├── ProjectWorkItems.kt
│ │ │ ├── RemoveElementsAfterKey.kt
│ │ │ ├── RepositoryHead.kt
│ │ │ ├── RepositoryTree.kt
│ │ │ ├── Tag.kt
│ │ │ ├── TopAppBar.kt
│ │ │ ├── TopBar.kt
│ │ │ ├── WorkItem.kt
│ │ │ └── WorkItems.kt
│ │ ├── navigation
│ │ │ ├── BottomBar.kt
│ │ │ ├── BottomBarScreen.kt
│ │ │ ├── NavigationGraph.kt
│ │ │ └── UIState.kt
│ │ ├── screens
│ │ │ ├── Home.kt
│ │ │ ├── PersonalProjects.kt
│ │ │ ├── Profile.kt
│ │ │ ├── project
│ │ │ │ ├── Commits.kt
│ │ │ │ ├── Issues.kt
│ │ │ │ ├── Members.kt
│ │ │ │ ├── MergeRequests.kt
│ │ │ │ ├── Overview.kt
│ │ │ │ ├── Pipelines.kt
│ │ │ │ └── Repository.kt
│ │ │ ├── Projects.kt
│ │ │ └── SplashScreen.kt
│ │ └── viewmodels
│ │ ├── ProfileViewModel.kt
│ │ └── project
│ │ ├── IssuesViewModel.kt
│ │ ├── MembersViewModel.kt
│ │ ├── PersonalProjectsViewModel.kt
│ │ ├── PipelinesViewModel.kt
│ │ ├── ProjectMRsViewModel.kt
│ │ ├── ProjectsViewModel.kt
│ │ └── repository
│ │ └── RepositoryViewModel.kt
│ └── test
│ └── java
│ └── com
│ └── ahtat204
│ └── gitlab
│ ├── data
│ │ └── remote
│ │ └── repositories
│ │ └── graphql
│ │ └── ApolloGraphQLRepositoryTest.kt
│ ├── presentation
│ │ └── viewmodels
│ │ ├── ProfileViewModelTest.kt
│ │ ├── project
│ │ │ ├── IssuesViewModelTest.kt
│ │ │ ├── MembersViewModelTest.kt
│ │ │ ├── PersonalProjectsViewModelTest.kt
│ │ │ ├── PipelinesViewModelTest.kt
│ │ │ ├── ProjectMRsViewModelTest.kt
│ │ │ ├── ProjectsViewModelTest.kt
│ │ │ └── repository
│ │ │ └── RepositoryViewModelTest.kt
│ │ └── testBase.kt
│ └── reponses
│ ├── json
│ │ ├── mockedAllProjects.kt
│ │ ├── mockedBranches.kt
│ │ ├── mockedCommits.kt
│ │ ├── mockedIssues.kt
│ │ ├── mockedMembers.kt
│ │ ├── mockedMrs.kt
│ │ ├── mockedPipelines.kt
│ │ ├── mockedProject.kt
│ │ ├── mockedProjects.kt
│ │ └── mockedRepository.kt
│ └── objects
│ ├── mockedAllProjects.kt
│ ├── mockedBranches.kt
│ ├── mockedCommits.kt
│ ├── mockedIssues.kt
│ ├── mockedMembers.kt
│ ├── mockedMRs.kt
│ ├── mockedProfile.kt
│ ├── mockedProject.kt
│ ├── mockedProjects.kt
│ ├── mockProjectPipelinesData.kt
│ └── mockRepository.kt
├── ARCHITECTURE.md
├── build.gradle.kts
├── gradle
│ ├── libs.versions.toml
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── history.jpg
├── home.jpg
├── homescreen.jpg
├── issues.jpg
├── members.jpg
├── mrs.jpg
├── personalprojects.jpg
├── profile.jpg
├── projectdetails.jpg
├── projectlist.jpg
├── projectsScreen.jpg
├── README.md
├── repository.jpg
└── settings.gradle.kts
# secrets.properties
CLIENT_ID:# this the Gitlab OAuth2 ClientID you get when creating an application on Gitlab , you define scope, redirect URL , you also get a Client Secret as well Key dependencies are managed in gradle/libs.versions.toml. Update versions as needed:
- Apollo Kotlin: GraphQL client
- Jetpack Compose: UI framework
- Coil: Image loading library
- OkHttp: HTTP client with interceptors
- Material Design 3: Design components
- OAuth2 Flow: Secure authentication without storing passwords
- Encrypted Token Storage: Access tokens are encrypted using Android's Crypto API
- HTTPS Only: All API communications are encrypted
- ProGuard Rules: Code obfuscation for production builds
- Never commit API credentials to the repository
- Store OAuth secrets in a secure configuration file (not in version control)
- Regularly update dependencies for security patches
- Review GraphQL queries to minimize exposed data
This project follows Clean Architecture principles with a layered approach:
-
Presentation Layer (UI)
- Composable screens using Jetpack Compose
- ViewModels for state management
- Navigation graph for screen transitions
-
Domain Layer (Business Logic)
- Use cases for business operations
- Domain models
- Repository interfaces
-
Data Layer (Data Sources)
- Repository implementations
- Remote data sources (API)
- Local caching (if applicable)
- Interceptors for request/response handling
- MVVM: ViewModel-based state management
- Repository Pattern: Abstraction of data sources
- Dependency Injection: Using Hilt for DI
- Single Responsibility Principle: Each component has one responsibility
Contributions are welcome! Whether it's bug fixes, feature requests, or improvements, please follow these guidelines:
-
Fork the repository
git clone https://github.com/Ahtat204/Gitlab.git
-
Create a feature branch
git checkout -b feature/your-feature-name
-
Make your changes
- Follow Kotlin coding conventions
- Add comments for complex logic
- Test your changes locally
-
Commit with clear messages
git commit -m "feat: add awesome feature" # or git commit -m "fix: resolve issue with X"
-
Push to your fork
git push origin feature/your-feature-name
-
Open a Pull Request
- Provide a clear description of your changes
- Link to any related issues
- Include screenshots for UI changes
feat:- New featurefix:- Bug fixrefactor:- Code refactoringdocs:- Documentationstyle:- Code style (formatting, etc.)test:- Adding or updating testschore:- Build, dependencies, etc.
- Follow Kotlin coding conventions
- Use meaningful variable and function names
- Keep functions small and focused
- Add KDoc comments for public APIs
- GitLab for the GraphQL API
- Jetpack Compose for the modern UI framework
- Apollo Kotlin for GraphQL client
- The Android development community
Have questions or found a bug?
- Open an Issue
- Check existing issues for similar problems
- Provide detailed error messages and reproduction steps









