Skip to content

Contributing

Thank you for your interest in contributing to Shipedge Warehouse Pro! This guide helps you understand the project structure, coding standards, and development process. Following these guidelines ensures consistency and quality across the codebase.

This guide covers:

  • Development environment setup
  • Code standards and conventions
  • Architecture patterns (Legacy vs MVP)
  • Testing guidelines
  • Pull request process
  • Best practices

Java Development

The project uses Java as the primary language with Kotlin support. You should be familiar with Android development and Java programming.

Android Studio

Use Android Studio for development. The project requires Gradle 4.0.0 and Android SDK API 21-29.

Hybrid Architecture

Understand both legacy patterns (Activities + AsyncTasks) and modern MVP architecture. New features should use MVP when possible.

Production App

This is a production application used in real warehouses. All changes must be tested thoroughly before deployment.

Required Software:

  • Android Studio - Latest stable version (compatible with Gradle 4.0.0)
  • Java JDK - Version 8 or higher
  • Android SDK - API 21 (minimum) and API 29 (target)
  • Gradle - Version 4.0.0 (included in project)

Recommended:

  • Git for version control
  • Android emulator or physical device for testing
  • Bluetooth scanner for hardware testing (if working on scanner features)
  1. Clone the repository

    Clone the repository to your local machine:

    Terminal window
    git clone [repository-url]
    cd Android-Documentation/pro
  2. Open in Android Studio

    Open the pro directory in Android Studio. Android Studio will automatically:

    • Sync Gradle files
    • Download dependencies
    • Index the codebase
  3. Configure SDK

    Ensure you have the required SDK versions installed:

    • Minimum SDK: API 21 (Android 5.0 Lollipop)
    • Target SDK: API 29 (Android 10)
    • Compile SDK: API 33
  4. Sync Gradle

    Wait for Gradle sync to complete. This downloads all dependencies including:

    • AndroidX libraries
    • Retrofit for API calls
    • EventBus for event handling
    • Material Design components
  5. Build the project

    Build the project to verify setup:

    Terminal window
    ./gradlew build

    Or use Android Studio: Build → Make Project

  6. Run on device/emulator

    Install and run the app on an emulator or physical device to verify everything works.

Key Build Settings:

android {
useLibrary 'org.apache.http.legacy'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
}
// Move the tests to tests/java, tests/res, etc...
androidTest.setRoot('tests')
// Move the build types to build-types/<type>
// For instance, build-types/debug/java, build-types/debug/AndroidManifest.xml, ...
// This moves them out of them default location under src/<type>/... which would
// conflict with src/ being used by the main source set.
// Adding new build types or product flavors should be accompanied
// by a similar customization.
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
compileSdkVersion 33
defaultConfig{
minSdkVersion 21
multiDexEnabled true
targetSdkVersion 34
}
}

Classes:

  • Activities: *Activity.java (e.g., PickActivity.java, MyRep.java)
  • Fragments: *Fragment.java (e.g., CycleCountDetailFragment.java)
  • Adapters: MyAdapter*.java (e.g., MyAdapterListOrder.java)
  • API Classes: ConnectToDataBaseServer*.java (e.g., ConnectToDataBaseServerReplenishment.java)
  • Models: PascalCase (e.g., Order.java, Product.java, Bin.java)
  • Presenters (MVP): *Presenter.java (interface), *PresenterClass.java (implementation)
  • Interactors (MVP): *Interactor.java (interface), *InteractorClass.java (implementation)

Variables:

  • Use camelCase for local variables
  • Use descriptive names (avoid abbreviations)
  • Example: shippingNumber, productId, binLocation

Packages:

  • Main package: shipedge.rep
  • MVP modules: shipedge.rep.{module}.{layer} (e.g., shipedge.rep.cycleCountActivity.mainModule.view)
  • Utilities: shipedge.rep.utils

Indentation:

  • Use 4 spaces for indentation (not tabs)
  • Consistent indentation throughout the file

Line Length:

  • Keep lines under 120 characters when possible
  • Break long lines logically

Comments:

  • Add comments for complex business logic
  • Use JavaDoc for public methods
  • Explain “why” not “what” (code should be self-documenting)

Example:

// Good: Explains business logic
// Filter out bins with zero quantity to avoid unnecessary API calls
if (bin.getQuantity() > 0) {
processBin(bin);
}
// Bad: States the obvious
// Check if quantity is greater than zero
if (bin.getQuantity() > 0) {
processBin(bin);
}

Legacy Pattern (Existing Features):

  • Activities contain UI and business logic
  • AsyncTask handles background API calls
  • Direct SQLite database access
  • Use this pattern when modifying existing legacy features

MVP Pattern (New Features):

  • View: Activity/Fragment implements view interface
  • Presenter: Handles business logic
  • Interactor: Handles data operations
  • Use this pattern for new features or major refactoring

When to Use Each:

  • Legacy: Modifying existing features, small bug fixes
  • MVP: New features, major refactoring, complex features

See Code Structure for detailed architecture information.

  1. Plan the feature

    Understand requirements and design the solution:

    • What problem does it solve?
    • Which architecture pattern (Legacy or MVP)?
    • What Activities/Fragments are needed?
    • What API endpoints are required?
  2. Create feature branch

    Create a branch from main:

    Terminal window
    git checkout -b feature/your-feature-name
  3. Set up module structure

    For MVP features:

    yourFeatureActivity/
    ├── mainModule/
    │ ├── view/
    │ ├── presenter/
    │ ├── model/
    │ └── events/
    ├── common/
    │ ├── dataAccess/
    │ └── params/
    └── dto/

    For Legacy features:

    • Add Activity in root package
    • Create API class if needed
    • Add layout files in res/layout/
  4. Implement the feature

    Follow the architecture pattern chosen:

    • Create Activities/Fragments
    • Implement business logic
    • Add API integration
    • Create layouts and resources
  5. Add string resources

    CRITICAL: Never hardcode strings. Always use strings.xml:

    res/values/strings.xml
    <string name="your_feature_title">Your Feature Title</string>

    Reference in Java:

    setTitle(getString(R.string.your_feature_title));
  6. Test thoroughly

    Test on multiple devices/emulators:

    • Test happy path
    • Test error cases
    • Test edge cases
    • Test with Bluetooth scanner (if applicable)
  7. Update documentation

    Update relevant documentation:

    • Feature documentation (if user-facing)
    • API documentation (if adding endpoints)
    • Code comments (for complex logic)

When modifying legacy code:

  1. Understand the current implementation

    • Read the Activity code
    • Understand the data flow
    • Check related API classes
    • Review layout files
  2. Make minimal changes

    • Don’t refactor unnecessarily
    • Maintain existing patterns
    • Keep changes focused
  3. Test regression

    • Test all existing functionality
    • Ensure no breaking changes
    • Verify edge cases still work
  4. Update documentation

    • Update user documentation if UI changes
    • Update code comments if logic changes

Creating API Connection Class:

public class ConnectToDataBaseServerYourFeature {
String warehouse;
public ConnectToDataBaseServerYourFeature(String param) {
this.warehouse = "https://" + Users.warehouse +
".shipedge.com/android/your-endpoint.php";
}
public YourModel[] getData() {
// HTTP POST request
// Parse JSON response
// Return model array
}
}

Using in Activity:

// In AsyncTask or background thread
ConnectToDataBaseServerYourFeature api =
new ConnectToDataBaseServerYourFeature(param);
YourModel[] data = api.getData();
// Update UI on main thread

Create Retrofit Service:

public interface YourFeatureService {
@POST("your-endpoint.php")
Call<YourResponse> getData(
@Body YourParams params,
@Header("token") String token
);
}

Create API Client:

public class YourFeatureAPI {
private YourFeatureService service;
public YourFeatureAPI(String token, String warehouse) {
service = HttpClient.createService(
YourFeatureService.class,
UtilService.getEndpoint(warehouse)
);
}
public void getData(YourParams params, EventCallback callback) {
Call<YourResponse> call = service.getData(params, token);
call.enqueue(new Callback<YourResponse>() {
// Handle response
});
}
}

See API Reference for detailed API documentation.

Always use string resources:

res/values/strings.xml
<string name="button_save">Save</string>
<string name="error_network">Network error. Please try again.</string>

Reference in Java:

button.setText(getString(R.string.button_save));
Toast.makeText(context, getString(R.string.error_network),
Toast.LENGTH_SHORT).show();

Reference in XML:

<Button
android:text="@string/button_save" />

Naming Convention:

  • Activity layouts: activity_*.xml
  • Fragment layouts: fragment_*.xml
  • List item layouts: item_*.xml
  • Dialog layouts: dialog_*.xml

Example:

  • activity_pick.xml - PickActivity layout
  • fragment_cycle_count_detail.xml - CycleCountDetailFragment layout
  • item_order_list.xml - Order list item layout
  • Place images in appropriate density folders:
    • drawable-mdpi/ - Medium density
    • drawable-hdpi/ - High density
    • drawable-xhdpi/ - Extra high density
    • drawable-xxhdpi/ - Extra extra high density
  • Use vector drawables when possible
  • Optimize images for mobile

Test Checklist:

  • Feature works on minimum SDK (API 21)
  • Feature works on target SDK (API 29)
  • Test with Bluetooth scanner (if applicable)
  • Test offline scenarios
  • Test error handling (network errors, invalid data)
  • Test edge cases (empty lists, null values)
  • Test on different screen sizes
  • Test portrait orientation (app is portrait-only)

Network Testing:

  • Test with good connection
  • Test with slow connection
  • Test with no connection (offline mode)
  • Test connection timeout scenarios

Data Testing:

  • Test with valid data
  • Test with invalid data
  • Test with empty data
  • Test with large datasets

Hardware Testing:

  • Test Bluetooth scanner integration
  • Test camera functionality (if applicable)
  • Test on different device models

Checklist:

  • Code follows naming conventions
  • All strings use string resources
  • Code is tested manually
  • No hardcoded values
  • Comments added for complex logic
  • Documentation updated (if needed)
  • No debug code or logs left in
  • Build succeeds without errors
  • Lint passes (if configured)

Include:

  • What: Description of changes
  • Why: Reason for changes
  • How: Implementation approach
  • Testing: How you tested
  • Screenshots: UI changes (if applicable)

Example:

## What
Added search functionality to Returns screen
## Why
Users need to search returns by tracking number, shipping number, or RMA
## How
- Added search fields to ReturnActivity
- Created API call to search endpoint
- Updated UI to display search results
## Testing
- Tested search by tracking number ✓
- Tested search by shipping number ✓
- Tested search by RMA ✓
- Tested error handling ✓
- Tested on API 21 and API 29 ✓

What reviewers check:

  • Code quality and style
  • Architecture pattern consistency
  • Error handling
  • Performance considerations
  • Security concerns
  • Test coverage
  • Documentation updates

Responding to feedback:

  • Address all comments
  • Ask questions if unclear
  • Update code accordingly
  • Re-test after changes

Use MVP for New Features

When creating new features, use MVP architecture pattern like Cycle Count and Load & Move modules. It provides better separation of concerns and testability.

Always Use String Resources

Never hardcode strings in Java code or XML layouts. Always use strings.xml for all user-facing text. This enables internationalization and consistency.

Handle Errors Gracefully

Always handle network errors, invalid data, and edge cases. Show user-friendly error messages from string resources.

Test on Real Devices

Test on physical devices when possible, especially for Bluetooth scanner features. Emulators may not accurately represent real-world behavior.

Keep Activities Focused

Each Activity should have a single responsibility. If an Activity becomes too large (1000+ lines), consider splitting into multiple Activities or using MVP pattern.

Document Complex Logic

Add comments for complex business logic, especially in legacy code. MVP pattern makes code self-documenting through clear separation.

Follow Existing Patterns

When modifying existing features, follow the existing patterns and conventions. Don’t introduce new patterns unless refactoring the entire feature.

Consider Performance

Be mindful of performance, especially for operations that run on the main thread. Use AsyncTask or background threads for network calls and heavy processing.

Hardcoding Strings:

// BAD
button.setText("Save");
Toast.makeText(context, "Error occurred", Toast.LENGTH_SHORT).show();

Blocking Main Thread:

// BAD
String result = apiCall.getData(); // Blocks UI thread
updateUI(result);

Ignoring Errors:

// BAD
try {
processData();
} catch (Exception e) {
// Silent failure
}

Large Activities:

// BAD - Activity with 2000+ lines mixing UI, business logic, and data access
public class MyRep extends Activity {
// 2000 lines of mixed concerns
}

Use String Resources:

// GOOD
button.setText(getString(R.string.button_save));
Toast.makeText(context, getString(R.string.error_occurred),
Toast.LENGTH_SHORT).show();

Use Background Threads:

// GOOD
new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
return apiCall.getData(); // Background thread
}
@Override
protected void onPostExecute(String result) {
updateUI(result); // Main thread
}
}.execute();

Handle Errors Properly:

// GOOD
try {
processData();
} catch (NetworkException e) {
showError(getString(R.string.error_network));
} catch (Exception e) {
Log.e(TAG, "Unexpected error", e);
showError(getString(R.string.error_unexpected));
}

Use MVP Pattern:

// GOOD - Separated concerns
public class CycleCountActivity extends AppCompatActivity
implements CycleCountView {
private CycleCountPresenter presenter;
// View only handles UI
}
public class CycleCountPresenter {
private CycleCountInteractor interactor;
// Presenter handles business logic
}

If you have questions:

  1. Check existing documentation
  2. Review similar features in the codebase
  3. Ask in pull request comments
  4. Contact the maintainers